home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Archive / Graphics / QuickDraw GX / IW-Half-Dither / source / NewApp.c < prev    next >
Encoding:
Text File  |  2000-09-28  |  95.5 KB  |  3,375 lines  |  [TEXT/MPS ]

  1. /*
  2.     copyright © 1991-1994 Apple Computer Inc.  All rights reserved.
  3.     
  4.     NewApp.c
  5.     This file contains all new API implementations for the ImageWriter driver.
  6.     
  7.     Modification history
  8.     03/19/91        TED                New file today
  9.     04/23/91        Sam Weiss        Changed Inherit to Forward
  10.     05/29/91        TED                Added manual feed and faster mode support
  11.     12/20/93        dmh                Sync'd with the shipping 1.0b3 GX driver.
  12.     03/24/94        Ken Hittleman    Updated manual feed to use gxTrayFeedInfo
  13.     03/30/94        Ken Hittleman    Added call to paper matching CheckStatus when switching to auto-feed
  14.     07/05/94        Ken Hittleman    Removed set color and page size from IW I path, which blew cookies on it
  15.     08/26/94        dmh                Sync'd with the shipping 1.0.1 GX driver.
  16.     05/21/96        Jason H-H        Updated for ETO#19/MW.
  17.     05/21/96        Don Swatman     Modifications for halftoning, dithering and plane seperations.
  18. */
  19.  
  20.  
  21. /**** DEFINE DEBUG ON ****/
  22. //#define DEBUGLEVEL DEBUGON
  23. /*************************/
  24.  
  25.  
  26. #include <Memory.h>
  27. #include <Errors.h>
  28. #include <ToolUtils.h>
  29. #include <Resources.h>
  30. #include <Packages.h>
  31. #include <GXPrinterDrivers.h>
  32. #include <GXPrinting.h>
  33. #include <FixMath.h>
  34. #include <GXMath.h>
  35. #include <GXGraphics.h>
  36. #include <GraphicsLibraries.h>
  37. #include <GXLayout.h>
  38. #include <CollectionLibrary.h>
  39. #include <JobFormatModeLibrary.h>
  40. #include <PaperTypeLibrary.h>
  41. #include <PicturesAndPICTLibrary.h>
  42.  
  43. #include "CommonDefines.h"
  44. #include "NewDriverProtos.h"
  45.  
  46.  
  47. /*    -----------------------------------------------------------------------
  48.  
  49.     __Startup__ contains our jump table to the overrides.
  50.     This code must be kept in sync with the assembly jump table
  51.     in NewApp.a and the gxOverrideType resources in NewApp.rsrc
  52.  
  53.     -----------------------------------------------------------------------    */
  54.  
  55.  
  56. #if defined(__MWERKS__)
  57. asm void __Startup__(void);
  58. asm void __Startup__(void)
  59.     {
  60.         dc.L    0                    // Reserved for owner count.
  61.  
  62.         // Universal messages
  63.         jmp SD_Initialize
  64.         jmp SD_ShutDown
  65.         jmp SD_DefaultPrinter
  66.         jmp SD_DefaultFormat
  67.         jmp SD_DefaultJob
  68.         jmp SD_JobFormatDialog
  69.         jmp SD_JobFormatModeQuery
  70.         jmp SD_RenderPage
  71.         jmp SD_OpenConnection
  72.         jmp SD_CloseConnection
  73.         jmp SD_StartSendPage
  74.         jmp SD_FinishSendPage
  75.         jmp SD_DumpBuffer
  76.         jmp SD_FreeBuffer
  77.         jmp SD_SetupImageData
  78.         jmp SD_JobIdle
  79.         jmp SD_JobPrintDialog
  80.         jmp SD_HandlePanelEvent
  81.  
  82.  
  83.         // Raster messages
  84.         jmp SD_PackageBitmap
  85.         jmp SD_LineFeed
  86.  
  87.         
  88.         rts                            // this is needed so __Startup__ symbol works
  89.     }
  90. #endif
  91.  
  92.  
  93. /* ------------------------------------------------------------------------------------    */
  94. /*    INTERNAL DEFINES                                                                    */
  95. /* ------------------------------------------------------------------------------------    */    
  96.  
  97. // positive error for aborting job and placing on hold
  98. #define kPutJobOnHoldErr            3
  99.  
  100. // timeout (in ticks) for the initial query
  101. #define kQueryTimeout                (7*60);
  102.  
  103. // things this specific driver puts into the DTP config file
  104. #define    kImageWriterConfigType        'ifig'
  105. #define kImageWriterConfigID        (0)            
  106. typedef struct
  107.     {
  108.         Boolean    hasColorRibbon;
  109.         Boolean    hasSheetFeeder;
  110.         Boolean    isImageWriterII;        // is this an ImageWriter II, or an older model?
  111.     } ImageWriterConfigRecord, *ImageWriterConfigPtr, ** ImageWriterConfigHandle;
  112.     
  113. /* Define special characters needed */
  114. #define ESCAPE                (char) 27
  115.  
  116. /* A record to hold a set margins command */
  117.  
  118. typedef struct SetMarginsRecord
  119.     {
  120.     char        cEscape;                    // ESCAPE character
  121.     char        cCommand;                    // Set Margins command character
  122.     char        cIndentDistance[4];            // number of dots to indent
  123.     } SetMarginsRecord, *SetMarginsPtr;
  124.  
  125. #define kSetMarginsCommand    (char)'F'        // ImageWriter II uses 'F' for tabbing
  126. #define kSetMarginsSize        6
  127.  
  128.  
  129. /*     Define a record that can hold one scan line's worth of data, 1280 will
  130.     only happen at 160 dpi. and 14 inch wide paper.   */
  131.  
  132. typedef struct ScanLineRecord
  133.     {
  134.     char            cColorEscape;                    // ESCAPE character
  135.     char            cSetColorCommand;                // Set color command
  136.     char            cColor;                            // The color
  137.     char            cEscape;                        // ESCAPE character
  138.     char            cCommand;                        // 'enter graphics' command
  139.     char            cLineLength[4];                    // number of dots to print
  140.     char            iTheData[2240];                    // Bits for the data, enough for one line's worth
  141.     } ScanLineRecord, *ScanLinePtr;
  142.  
  143.  
  144. #define kGraphicsCommand    (char)'G'        /* graphics printing command */
  145. #define kRepeatGroup        (char)'V'        /* repeat group character */
  146. #define kSetColorCommand     (char)'K'        /* Set color command */
  147. #define kGroupSize            6                /* Size of one group header */
  148.  
  149. #define kScanLineSize         3                /* NOTE: this is just the header size! */
  150.  
  151.  
  152. // Status flags for PAP status queries
  153. #define    kColorRibbonBit        0
  154. #define kSheetFeederBit        1
  155. #define kPaperOutBit        2
  156. #define kCoverOpenBit        3
  157. #define kOffLineBit            4
  158. #define kPaperJamBit        5
  159. #define kPrinterFaultBit    6
  160. #define kHeadMovingBit        7
  161. #define kPrinterBusyBit        8
  162.  
  163. #define kOutOfPaperMask            (  (0x8000 >> kPaperJamBit) | (0x8000 >> kCoverOpenBit) | (0x8000 >> kOffLineBit) )
  164. #define kPrinterOfflineMask        (  (0x8000 >> kOffLineBit) )
  165. #define kPrinterBusyMask        (  (0x8000 >> kPrinterBusyBit) )
  166. #define kHeadMovingMask            (  (0x8000 >> kHeadMovingBit) )
  167.  
  168. // Color pass
  169.  
  170. #define kYellowPass   1
  171. #define kMagentaPass  2
  172. #define kCyanPass     3
  173. #define kBlackPass    4
  174.  
  175. //-------------------------------------------------------------------
  176. // Structures and constants for the render options collection
  177. //
  178. // This is structured so it can be used by the gxExtendedDITLType
  179. // resource -'xdtl'. The types and allignment are significant.
  180. //
  181. // Booleans : unsigned char : These are byte alligned.
  182. // Pop-up   : short         : Word (2Byte) alligned
  183. // Float    : fixed         : Word (2Byte) alligned
  184. //-------------------------------------------------------------------
  185.  
  186. #define kDitherIt   0
  187. #define kHalfToneIt 1
  188.  
  189. #define kRenderOptsCyan    0
  190. #define kRenderOptsMagenta 1
  191. #define kRenderOptsYellow  2
  192. #define kRenderOptsBlack   3
  193.  
  194. struct CMYKRenderCollection
  195. {
  196. // Plane flags, set to true to print the plane
  197.     unsigned char cyanIsOn;
  198.     unsigned char magentaIsOn;
  199.     unsigned char yellowIsOn;
  200.     unsigned char blackIsOn;
  201.  
  202. // Set to "kDitherIt" for dithered output, or "kHalfToneIt" for half tone
  203.     unsigned char renderMode;
  204.     unsigned char fill1;
  205.     
  206. // used when in dither mode to select the level of dither
  207.     short ditherLevel;
  208.  
  209. // used when in half tone mode to select how to half tone
  210.     short dotType;
  211.     Fixed angles[4];
  212.     Fixed frequency[4];
  213.  
  214. };
  215. typedef struct CMYKRenderCollection CMYKRenderCollection;
  216.  
  217.  
  218. //<FF>
  219. /* ------------------------------------------------------------------------------------    */
  220. /*    INTERNAL ROUTINES                                                                */
  221. /* ------------------------------------------------------------------------------------    */
  222. void Long2Dec(long aLong, Ptr emitHere)
  223. /*
  224.     Converts a long into an ASCII string, padded with leading zeros.
  225. */
  226. {    
  227.     char    aString[10];
  228.     short    i, actualWidth, strLength;
  229.     
  230.     NumToString(aLong, (unsigned char*)aString);
  231.     
  232.     // Get the width of the string, check for being too small
  233.     strLength = aString[0];
  234.     actualWidth = strLength;
  235.     if (actualWidth < 4)
  236.         actualWidth = 4;
  237.         
  238.     // output the string, padding with the requested character
  239.     strLength = actualWidth-strLength;
  240.     for (i = 0; i < actualWidth; ++i)
  241.         {
  242.         *emitHere++ = (i < strLength) 
  243.             ? '0' : aString[(i+1)-(strLength)];
  244.         }
  245.         
  246. } // Long2Dec
  247.  
  248.  
  249. //<FF>
  250. /* ------------------------------------------------------------------------------------    */
  251. Boolean PrinterHasColorRibbon(gxPrinter thePrinter)
  252. /*
  253.     Returns true if the config file says that the printer is blessed with a color ribbon,
  254.     false if it is a black and white ribbon.
  255. */
  256. {
  257.     Boolean                        hasColor = true;
  258.     Str32                        deviceName;
  259.     OSErr                        anErr;
  260.     ImageWriterConfigHandle        configHandle;
  261.     
  262.     // if not formatting to a particular device, assume color ribbon, for widest range of colorSpaces
  263.     GXGetPrinterName(thePrinter, deviceName);
  264.     if (deviceName[0] != 0)
  265.         {
  266.         // if we are going to a particular device, assume no color, as that is more common
  267.         hasColor = false;
  268.         
  269.         anErr = GXFetchDTPData(deviceName, kImageWriterConfigType, kImageWriterConfigID, (Handle*)&configHandle);
  270.         if (anErr == noErr)
  271.             {
  272.             hasColor = (**configHandle).hasColorRibbon;
  273.             DisposHandle((Handle) configHandle);
  274.             }
  275.         }
  276.     
  277.     return(hasColor);
  278.     
  279. } // PrinterHasColorRibbon
  280.  
  281.  
  282. //<FF>
  283. /* ------------------------------------------------------------------------------------    */
  284. gxViewDevice    NewDeviceResolutionViewDevice(void)
  285. /*
  286.     This routine creates a viewDevice and gives it a scale factor in it's mapping
  287.     appropriate for this device (144 dpi in the case of the IW)
  288. */
  289. {
  290.     gxViewDevice        vd;
  291.     
  292.     // create the viewDevices with a fake bitmap
  293.     {
  294.     gxShape        tempBitmap;
  295.     gxBitmap        aBitmap;
  296.     
  297.     aBitmap.pixelSize     = 1;
  298.     aBitmap.rowBytes     = 0;
  299.     aBitmap.width         = 0;
  300.     aBitmap.height         = 0;
  301.     aBitmap.image         = (char*)gxMissingImagePointer;
  302.     aBitmap.space         = gxNoSpace;
  303.     aBitmap.set         = nil;
  304.     aBitmap.profile     = nil;
  305.     
  306.     tempBitmap = GXNewBitmap(&aBitmap, nil);
  307.     vd = GXNewViewDevice(gxScreenViewDevices, tempBitmap);
  308.     GXDisposeShape(tempBitmap);
  309.     }
  310.  
  311.     // setup a mapping for a 144 (2X) viewDevice
  312.     {
  313.     gxMapping    vdMapping;
  314.     
  315.     ResetMapping(&vdMapping);
  316.     ScaleMapping(&vdMapping, ff(2), ff(2), ff(0), ff(0));
  317.     
  318.     GXSetViewDeviceMapping(vd, &vdMapping);
  319.     }
  320.     
  321.     return(vd);
  322.     
  323. } // NewDeviceResolutionViewDevice
  324.  
  325. //<FF>
  326. /* ------------------------------------------------------------------------------------    */
  327. Boolean    JobIsBest(long *imagewriterOptions)
  328. /*
  329.     Returns true if the current job is a final quality mode job, else returns false.
  330.     Also, returns the imagewriter rendering options.
  331. */
  332. {
  333.     Boolean            isFinal;
  334.     gxQualityInfo    jobQualitySettings;
  335.     long            itemSize = sizeof(jobQualitySettings);
  336.     OSErr            status;
  337.     Collection        jobCollection;
  338.     
  339.     // cache the collection
  340.     jobCollection = GXGetJobCollection(GXGetJob());
  341.     
  342.     // find out the info
  343.         
  344.     isFinal = false;
  345.     
  346.     status = GetCollectionItem(jobCollection, 
  347.                                     gxQualityTag, gxPrintingTagID, 
  348.                                     &itemSize, &jobQualitySettings);
  349.     
  350.     if ( (status == noErr) && (jobQualitySettings.currentQuality == (jobQualitySettings.qualityCount-1)) )
  351.         isFinal = true;
  352.     
  353.     // we default to super res
  354.     *imagewriterOptions = kSuperRes;
  355.     itemSize = sizeof(imagewriterOptions);
  356.     status = GetCollectionItem(jobCollection, 
  357.                                     DriverCreator, 0, 
  358.                                     &itemSize, imagewriterOptions);
  359.                 
  360.     // and return the job quality mode
  361.     return(isFinal);
  362.     
  363. } // JobIsBest
  364.  
  365.  
  366. //<FF>
  367. /* ------------------------------------------------------------------------------------    */
  368.  
  369. OSErr    DoTheQuery(unsigned short * statusReturn, Boolean papStatus)
  370. /*
  371.     Returns in statusString the current status for the printer.  Returns various
  372.     errors from IO package if the printer's status could not be found.
  373. */
  374. {
  375.     OSErr                anErr = noErr;
  376.     long                statusLength;                    // status string size
  377.     SpecGlobalsHdl         hGlobals = GetMessageHandlerInstanceContext();
  378.     char                cmdData[4];
  379.     Str255                theTerminatorStr;
  380.  
  381.     theTerminatorStr[0] = 0x01;        //    teminator codes for query
  382.     theTerminatorStr[1] = 0x0D;        //    CR == 0x0D
  383.     cmdData[0] =    0x1B;            // cmdData control codes to query ImageWriter II 
  384.     cmdData[1] =     0x3F;
  385.  
  386.     // default to a clear status
  387.     *statusReturn = 0;
  388.  
  389.     // send the query
  390.     if (papStatus)
  391.     {
  392.         char    statusString[255];                // returned string
  393.         
  394.         // According to the old IW driver, sometimes it will return all of the bits
  395.         // set.  This is an error, but we can just try again.
  396.         do
  397.         {
  398.             statusLength = 255;
  399.             anErr = Send_GXGetDeviceStatus(nil, 0, statusString, &statusLength, nil);
  400.         } while ( (anErr == noErr) && (statusString[0] == 0xFF) );
  401.         // return the printer status bits in the PAP case
  402.         *statusReturn = *(unsigned short*)&statusString[0];
  403.     }
  404.     else
  405.     {
  406.         char    statusString[8];                // returned string
  407.  
  408.         if ((**hGlobals).isImageWriterII)
  409.         {
  410.             statusLength = 8; // max number of characters to get back
  411.             anErr = Send_GXGetDeviceStatus((Ptr)&cmdData, 2, statusString, &statusLength, theTerminatorStr);
  412.                 
  413.             if ( anErr == gxAioTimeout)
  414.             {
  415.                 *statusReturn = kPrinterOfflineMask;
  416.                 anErr = noErr;
  417.             }
  418.             else
  419.             {
  420.                 if (anErr == noErr)
  421.                 {
  422.                     // generate printer status bits in the serial case
  423.                     if (statusString[4] == 'C')
  424.                         *statusReturn |= 0x8000 >> kColorRibbonBit;
  425.                     if ( (statusString[5] == 'F') || (statusString[4] == 'F') )
  426.                         *statusReturn |= 0x8000 >> kSheetFeederBit;
  427.                 }
  428.             }
  429.         }
  430.     }
  431.         
  432.     nrequire(anErr, Send_GXGetDeviceStatus);
  433.  
  434. // FALL THROUGH EXCEPTION HANDLING    
  435. Send_GXGetDeviceStatus:
  436.     
  437.     return(anErr);
  438.  
  439. } // DoTheQuery
  440.  
  441. //<FF>
  442. /* ------------------------------------------------------------------------------------    */
  443. OSErr FetchStatusString(unsigned short * statusReturn, Boolean papStatus, Boolean doRetry)
  444. /*
  445.     Returns in statusString the current status for the printer.  Returns various
  446.     errors from IO package if the printer's status could not be found.
  447.     
  448.     Handles reporting error conditions to the user.
  449. */
  450. {
  451.     OSErr                anErr;
  452.     SpecGlobalsHdl         hGlobals = GetMessageHandlerInstanceContext();
  453.     
  454.     anErr = DoTheQuery(statusReturn, papStatus);        
  455.     nrequire(anErr, Send_GXGetDeviceStatus);
  456.     
  457.     // printer offline?
  458.     if (     
  459.         (doRetry) &&
  460.         ( ((*statusReturn) & kPrinterOfflineMask) != 0 )  
  461.         )
  462.         {
  463.         gxStatusRecord        theStat;
  464.         gxStatusRecord        *pStat = &theStat;
  465.         Boolean                printerIsFixed = false;
  466.         
  467.         pStat->statusOwner    = 'drvr';
  468.         pStat->statResId     = kDriverStatus;        
  469.         pStat->statResIndex = kCheckOnline;            
  470.         pStat->bufferLen      = 0;
  471.         pStat->dialogResult = 0;    // ORIGINALLY SET TO ===> nil;
  472.         
  473.  
  474.         // keep sending the user the alert until either
  475.         //  a) the problem resolves itself
  476.         //  b) the user responds via the dialog
  477.         //  c) some other (fatal) error happens
  478.         do
  479.             {
  480.             
  481.             // tell the user
  482.             anErr = GXAlertTheUser(pStat);
  483.             
  484.             // based on the user's response, continue or cancel
  485.             switch (pStat->dialogResult)
  486.                 {
  487.                 case ok:
  488.                     // retry
  489.                     break;
  490.                     
  491.                 case cancel:
  492.                     anErr = gxPrUserAbortErr;
  493.                     break;
  494.                     
  495.                 case 3:
  496.                     anErr = kPutJobOnHoldErr;
  497.                     break;
  498.                 }
  499.                 
  500.             // error to return from next idle
  501.             (**hGlobals).idleError = anErr;
  502.  
  503.             // if printer got suddenly turned online, do an OK
  504.             if ( (anErr == noErr) && ((papStatus) || (pStat->dialogResult == ok)) )
  505.                 {
  506.                 pStat->dialogResult = 0;    // ORIGINALLY SET TO ===> nil;
  507.                 (void) DoTheQuery(statusReturn, papStatus);        
  508.                 if (     
  509.                     ( ((*statusReturn) & kPrinterOfflineMask) == 0 ) 
  510.                     )
  511.                     {
  512.                     printerIsFixed = true;
  513.                     pStat->dialogResult = ok;
  514.                     anErr = noErr;
  515.                     }
  516.                 }
  517.                 
  518.             } while ((anErr == noErr) && (pStat->dialogResult == 0)); // WAS ORIGINALLY ====>  (pStat->dialogResult == nil)
  519.  
  520.         // printer is okay -- no error
  521.         if (printerIsFixed)
  522.             anErr = noErr;
  523.         
  524.         // display "sending data to the printer" message
  525.         if (anErr == noErr)
  526.             anErr = GXReportStatus(kDriverStatus, kSendingData);
  527.         }
  528.  
  529. // FALL THROUGH EXCEPTION HANDLING    
  530. Send_GXGetDeviceStatus:
  531.     
  532.     return(anErr);
  533.     
  534. } // FetchStatusString
  535.  
  536. //<FF>
  537. /* ------------------------------------------------------------------------------------    */
  538. OSErr UpdateConfiguration(void)
  539. /*
  540.     This routine queries the printer for its hardware configuration (color ribbon and
  541.     sheet feeder options), and stores that info into the configuration file.
  542. */
  543. {
  544.     SpecGlobalsHdl                 hGlobals;
  545.     Str32                        deviceName;
  546.     OSErr                        anErr = noErr;
  547.     ImageWriterConfigHandle        configHandle;
  548.     ImageWriterConfigPtr        configPtr;
  549.     Boolean                        isImageWriterII;
  550.     ResType                        commType;
  551.     
  552.     hGlobals = GetMessageHandlerInstanceContext();    
  553.     isImageWriterII = false;
  554. // find out what we are printing to, and how we are connected
  555.     GXGetPrinterName(GXGetJobOutputPrinter(GXGetJob()), deviceName);
  556.     anErr = GXFetchDTPData(deviceName, gxDeviceCommunicationsType, gxDeviceCommunicationsID, (Handle*)&configHandle);
  557.     nrequire(anErr, FetchCommType);
  558.     commType = **(ResType**)configHandle;
  559.     DisposHandle((Handle) configHandle);
  560.     
  561.     
  562.     // store away the communications type for future use
  563.     //{
  564.     //    SpecGlobalsHdl             hGlobals = GetMessageHandlerInstanceContext();
  565.     //    
  566.     //    (**hGlobals).commType = commType;
  567.     //}
  568.     
  569.     // find out the original configuration
  570.     if (GXFetchDTPData(deviceName, kImageWriterConfigType, kImageWriterConfigID, (Handle*)&configHandle) == noErr)
  571.     {
  572.         // remember if we thought we had an IW2 when we started
  573.         configPtr = *configHandle;
  574.         (**hGlobals).isImageWriterII = isImageWriterII = configPtr->isImageWriterII;
  575.         DisposeHandle((Handle) configHandle);
  576.  
  577.         // if we aren't an ImageWriter II, bail out now - because the timeout takes two minutes!
  578.         if (!isImageWriterII)
  579.         {
  580.             return(noErr);            
  581.         }
  582.     }
  583.     else
  584.     {        
  585.         if (commType == 'PPTL')
  586.         {
  587.             isImageWriterII = true;
  588.         }    
  589.         // Assume IW 2 so we do the query for real
  590.         (**hGlobals).isImageWriterII = true;
  591.     }
  592.         
  593.     // make a handle to hold our configuration information for the printer
  594.     configHandle = (ImageWriterConfigHandle) NewHandle(sizeof(ImageWriterConfigRecord) );
  595.     anErr = MemError();
  596.     nrequire(anErr, NewHandle);
  597.     
  598.     // setup the default for the device - in case the query fails
  599.     configPtr = *configHandle;
  600.     configPtr->hasColorRibbon = false;
  601.     configPtr->hasSheetFeeder = false;
  602.     configPtr->isImageWriterII = true;
  603.     
  604.     // send initial data first to make sure IO handshaking is working,
  605.     // to load the first sheet of paper into the feeder (if any),
  606.     // and to take up "gear lash" in the device.  This is copied from
  607.     // what the old driver did.  Not doing this will cause the sheet
  608.     // feeder not to feed the initial page of data.
  609.     {
  610.     char    sendBuffer[11];
  611.     
  612.     // <CR>
  613.     sendBuffer[0] = 0x0D;
  614.     
  615.     // linefeed size = 18/144th
  616.     sendBuffer[1] = ESCAPE;
  617.     sendBuffer[2] = 'T';
  618.     sendBuffer[3] = '1';
  619.     sendBuffer[4] = '8';
  620.     
  621.     // reverse line feed
  622.     sendBuffer[5] = ESCAPE;
  623.     sendBuffer[6] = 'r';
  624.     sendBuffer[7] = 0x0A;
  625.     
  626.     // forward line feed
  627.     sendBuffer[8] = ESCAPE;
  628.     sendBuffer[9] = 'f';
  629.     sendBuffer[10] = 0x0A;
  630.     
  631.     anErr = Send_GXWriteData(sendBuffer, 11);
  632.     nrequire(anErr, Failed_SendInitialData);
  633.     }
  634.     
  635.     {
  636.         unsigned short    statusReturn;
  637.         
  638.         // query the device
  639.         if ((isImageWriterII) && (commType == 'SPTL') )
  640.             (**hGlobals).idleTimeout = TickCount() + kQueryTimeout;
  641.         anErr = FetchStatusString(&statusReturn, (Boolean)(commType == 'PPTL'), isImageWriterII);
  642.  
  643.         if ( (anErr == noErr) && ( (statusReturn & kPrinterOfflineMask) != 0 )  )
  644.             anErr = gxAioTimeout;
  645.         (**hGlobals).idleTimeout = 0;
  646.         GXReportStatus(kDriverStatus, kSendingData);
  647.         
  648.         // and scan the string looking for information about printer kind and options
  649.         configPtr = *configHandle;
  650.         if ( anErr == gxAioTimeout )
  651.         {
  652.             // if we timeout and we don't know the printer kind - assume IW1
  653.             if (!isImageWriterII)
  654.             {
  655.                 anErr = noErr;
  656.                 isImageWriterII = configPtr->isImageWriterII = false;
  657.             }
  658.         }
  659.         else
  660.         {
  661.             isImageWriterII = true;
  662.             configPtr->hasColorRibbon = (statusReturn & (0x8000 >> kColorRibbonBit)) != 0;
  663.             configPtr->hasSheetFeeder = (statusReturn & (0x8000 >> kSheetFeederBit)) != 0;
  664.         }
  665.         nrequire(anErr, FetchStatusString);
  666.     }
  667.     
  668.     // Remember if this was an ImageWriter II after the query
  669.     (**hGlobals).isImageWriterII = isImageWriterII;
  670.     
  671.     // write out the new configuration
  672.     anErr = GXWriteDTPData(deviceName, kImageWriterConfigType, kImageWriterConfigID, (Handle)configHandle);
  673.     
  674.     
  675. // CLEANUP EXCEPTION HANDLING
  676. FetchStatusString:
  677. Failed_SendInitialData:
  678.     DisposHandle((Handle) configHandle);
  679.     
  680. NewHandle:
  681. Send_GXWriteData:
  682. FetchCommType:
  683.     return(anErr);
  684.     
  685. } // UpdateConfiguration
  686.  
  687.  
  688. /* ------------------------------------------------------------------------------------    */
  689. OSErr WriteDraftChars(long **draftTable, unsigned char *draftChar, long numChars)
  690. /*
  691.     This routine writes out a single character in the native set of the printer.
  692.     It uses a table that's part of the driver to do the right thing in order to generate this
  693.     character.
  694. */
  695. {
  696.     OSErr        anErr = noErr;
  697.     char        outputChars[20];                // a maximum of 20 characters can be generated
  698.     short        charCount;                    
  699.     
  700.     // For each character in the buffer, determine how to map the character to a draft character
  701.     for (; numChars > 0; --numChars, ++draftChar)
  702.     {
  703.         // No characters yet for this output character
  704.         charCount = 0;
  705.             
  706.         // Only consider characters in the printable range
  707.         if (*draftChar >= 0x20)
  708.         {
  709.             unsigned long    draftControl = (*draftTable)[*draftChar-0x20];    // Fetch native mode long word corresponding to this character
  710.             unsigned char    outChar;
  711.             unsigned char    nationalSet;
  712.             short                i;
  713.             
  714.             // For each word which composes the native mode long word 
  715.             for (i = 1; i >= 0; --i)
  716.             {
  717.                 // Should we send a backspace character (to overstrike)?
  718.                 if ( (draftControl & 0x80000000) != 0 )
  719.                     outputChars[charCount++] = 0x08;
  720.                 
  721.                 outChar = (draftControl >> 16) & 0xFF;
  722.                 if (outChar != 0)
  723.                 {
  724.                     // Determine the national character set to select
  725.                     nationalSet = (draftControl >> 24) & 0xF;    
  726.     
  727.                     //    Is this character in the standard, built-in character set?
  728.                     if (nationalSet == 0)
  729.                     {
  730.                         outputChars[charCount++] = outChar;
  731.                     }
  732.                     else    //    T => Must select a foreign language character set 
  733.                     {
  734.                         outputChars[charCount++] = 0x1B;
  735.                         outputChars[charCount++] = 0x44;
  736.                         outputChars[charCount++] = nationalSet;
  737.                         outputChars[charCount++] = 0x00;
  738.                         outputChars[charCount++] = outChar;
  739.                         outputChars[charCount++] = 0x1B;                // We always switch back to the kAmerican character set
  740.                         outputChars[charCount++] = 0x5A;
  741.                         outputChars[charCount++] = 0x07;
  742.                         outputChars[charCount++] = 0x00;
  743.                     }
  744.                 }
  745.                 
  746.                 // Take the next (low) word and process it (if we're not all done)
  747.                 draftControl <<= 16;
  748.             }    
  749.         }
  750.             
  751.         // If we generated any data, send it out now
  752.         if (charCount > 0)
  753.             anErr = Send_GXBufferData(outputChars, charCount, gxNoBufferOptions);
  754.     }
  755.         
  756.     return(anErr);    
  757.     
  758. } // WriteDraftChars
  759.  
  760. /* ------------------------------------------------------------------------------------    */
  761. OSErr GetPointerThisBig(Ptr *theBuff, long numBytes) 
  762. {
  763.     OSErr        anErr = noErr;
  764.     
  765.     if (*theBuff != nil)
  766.     {
  767.         if ( GetPtrSize(*theBuff) < numBytes )    //    T => Won't be big enough; make a new one
  768.         {
  769.             DisposPtr(*theBuff);
  770.             *theBuff = nil;
  771.         }
  772.     }
  773.  
  774.     if (*theBuff == nil)
  775.     {
  776.         *theBuff = NewPtrClear(numBytes);
  777.         anErr = MemError();
  778.     }
  779.     
  780.     return(anErr);
  781.     
  782. } // GetPointerThisBig
  783.  
  784. /* ------------------------------------------------------------------------------------    */
  785. OSErr GetTextAndPosition(    gxShape            theShape, 
  786.                             Ptr                *theChars, 
  787.                             long            *numChars, 
  788.                             gxPoint            *textPosition)
  789. {
  790.     OSErr        anErr = noErr;
  791.     long        textLength;
  792.     
  793.     // Determine the size of the text data and the position of the text
  794.     textLength = GXGetLayout(theShape, nil, nil, nil, nil, nil, nil, nil, nil, textPosition);
  795.  
  796.     // Make sure we have a buffer pointer large enough to hold all of the data
  797.     
  798.     anErr = GetPointerThisBig(theChars, textLength);
  799.     require(anErr == noErr, CantAllocTextBuff);
  800.     
  801.     // Now we retrieve the text
  802.     GXGetLayout(theShape, *theChars, nil, nil, nil, nil, nil, nil, nil, nil);
  803.     
  804.     // Remember the number of characters in the shape
  805.     *numChars = textLength;
  806.     
  807.  
  808. /******* Clean-up *******/
  809.  
  810. CantAllocTextBuff:
  811.     return(anErr);
  812.     
  813. } // GetTextAndPosition
  814.  
  815. /* ------------------------------------------------------------------------------------    */
  816. OSErr PrintPageInDraftMode(gxShape thePage, gxRasterImageDataHdl imageData)
  817. {
  818.     OSErr                    anErr = noErr;
  819.     long                    i;
  820.     long                    numItems;
  821.     Fixed                    currYPos = ff(0);
  822.     Ptr                        theChars = nil;
  823.     long                    numChars = 0;
  824.     gxPoint                    textPosition;
  825.     Fixed                    oldTextSize = ff(0);
  826.     SpecGlobalsHdl             hGlobals = GetMessageHandlerInstanceContext();
  827.     
  828.     // Since the page picture we need to process is a picture shape that's embedded in
  829.     // thePage (a shape containing one item => a picture), we need to extract the real
  830.     // page picture from thePage.
  831.     
  832.     thePage = GetPictureItem(thePage, 1, nil, nil, nil, nil);
  833.     numItems = GXGetPicture(thePage, nil, nil, nil, nil);
  834.     
  835.     // For each shape within the picture, check its type and process it accordingly
  836.     
  837.     for (i = 1; i <= numItems; ++i)
  838.     {
  839.         gxShape                theShape;
  840.         short                theType;
  841.                 
  842.         theShape = GetPictureItem(thePage, i, nil, nil, nil, nil);
  843.         theType = GXGetShapeType(theShape);
  844.         
  845.         if (theType == gxLayoutType)    //    T => We have a layout shape
  846.         {
  847.             Fixed        textSize;
  848.             char        buff[12];
  849.             char        theFace;
  850.             short        cmndBuffSz;
  851.             
  852.             // First determine the style in which we're printing
  853.             
  854.             theFace = GetStyleCommonFace( GXGetShapeStyle(theShape) );
  855.             
  856.             buff[0] = ESCAPE;
  857.             if ( (theFace & bold) != 0 )    //    T => Turn bold facing on
  858.                 buff[1] = '!';
  859.             else                                    //    T => Turn it off
  860.                 buff[1] = '"';
  861.             
  862.             buff[2] = ESCAPE;
  863.             if ( (theFace & underline) != 0 )    //    T => Turn underline facing on
  864.                 buff[3] = 'X';
  865.             else                                            //    T => Turn it off
  866.                 buff[3] = 'Y';
  867.                 
  868.             cmndBuffSz = 4;
  869.             
  870.             // Next determine if we need to change the size of the font being used
  871.             
  872.             textSize = GXGetShapeTextSize(theShape);
  873.             if (textSize != oldTextSize)    //    T => Must issue LQ command to change font size
  874.             {
  875.                 buff[4] = ESCAPE;                //    The first escape command selects black color
  876.                 buff[5] = kSetColorCommand;
  877.                 buff[6] = '0';
  878.                 
  879.                 buff[7] = ESCAPE;                //    The second escape command selects a draft font
  880.                 buff[8] = 'a';
  881.                 buff[9] = '1';
  882.                 
  883.                 buff[10] = ESCAPE;                //    The third escape command selects the character pitch
  884.                 
  885.                 if ( textSize <= ff(10) )    //    T => Select 10 cpi
  886.                 {
  887.                     buff[11] = 'N';
  888.                 }
  889.                 else    //    T => All other sizes get mapped to 12 cpi
  890.                 {
  891.                     buff[11] = 'E';
  892.                 }
  893.                 
  894.                 // Remember the last text size
  895.                 oldTextSize = textSize;    
  896.                 
  897.                 // Adjust the size of the data to be sent to the printer
  898.                 cmndBuffSz += 8;
  899.             }
  900.             // else - no change in font size
  901.             
  902.             // Send the commands to the printer
  903.             anErr = Send_GXBufferData(buff, cmndBuffSz, gxDontSplitBuffer);
  904.             require(anErr == noErr, CantSendFontCmnd);
  905.  
  906.             // Get the ASCII text and the starting position of the data
  907.             anErr = GetTextAndPosition(theShape, &theChars, &numChars, &textPosition);
  908.             require(anErr == noErr, CantGetTextAndPos);
  909.             
  910.             if ( (currYPos != ff(0)) && (currYPos != textPosition.y) )    //    T => Moving to a lower line, finish the last ;line with a CR
  911.             {
  912.                 char        c = 0x0D;
  913.                 
  914.                 anErr = Send_GXBufferData(&c, 1, gxNoBufferOptions);
  915.                 require(anErr == noErr, CantSendCRCmnd);
  916.             }
  917.             
  918.             // Position the print head to the proper location on the page
  919.             {
  920.                 gxMapping                theMapping;
  921.                 long                    lineFeedSize;
  922.                 Str255                    positionCmndsBuff;
  923.                 unsigned long            bytesInBuff = 0;
  924.                 unsigned char            *p;
  925.  
  926.                 GXGetShapeMapping(theShape, &theMapping);
  927.                 MapPoints(&theMapping, (long) 1, &textPosition);    //    Just map the first point
  928.                 
  929.                 // Now position the print head vertically
  930.  
  931.                 lineFeedSize = (textPosition.y - currYPos) >> 16;
  932.                 anErr = Send_GXRasterLineFeed(&lineFeedSize, (char*)positionCmndsBuff, &bytesInBuff, imageData);
  933.                 require(anErr == noErr, CantEmitLineFeeds);
  934.                 
  935.                 // Update the current Y position pointer on the page
  936.                 currYPos = textPosition.y;
  937.  
  938.                 // Now position the print head horizontally on the page
  939.  
  940.                 p = &positionCmndsBuff[bytesInBuff];        
  941.                 *p++ = ESCAPE;
  942.                 *p++ = 'F';
  943.                 Long2Dec((*hGlobals)->leftMargin + FixedToInt(textPosition.x), (char*)p);    // Convert left margin into ASCII and place it at the start of the scan line
  944.                 
  945.                 // Update the number of bytes in the buffer
  946.                 bytesInBuff += 6;
  947.  
  948.                 // Send the positioning info to the printer
  949.                 anErr = Send_GXBufferData((char*)positionCmndsBuff, bytesInBuff, gxDontSplitBuffer);
  950.                 require(anErr == noErr, CantSendPositionCmnds);
  951.             }
  952.             
  953.             // Now we send the text data to the printer
  954.             anErr = WriteDraftChars((long **) (*hGlobals)->draftTable, (unsigned char*)theChars, numChars);
  955.             require(anErr == noErr, CantWriteChars);
  956.         }
  957.     }    // for
  958.  
  959.     // Send one last CR to wrap the last line (if there was one)
  960.     {
  961.         char        c = 0x0D;
  962.         
  963.         anErr = Send_GXBufferData(&c, 1, gxNoBufferOptions);
  964.     }
  965.  
  966.  
  967. /******* Clean-up *******/
  968.  
  969. CantWriteChars:
  970. CantSendPositionCmnds:
  971. CantEmitLineFeeds:
  972. CantSendCRCmnd:
  973. CantGetTextAndPos:
  974. CantSendFontCmnd:
  975.     if (theChars != nil)
  976.         DisposPtr(theChars);
  977.                 
  978.     return(anErr);
  979.     
  980. } // PrintPageInDraftMode 
  981.  
  982. //<FF>
  983. /* ------------------------------------------------------------------------------------    */
  984. /*    SPECIFIC DRIVER UNIVERSAL OVERRIDES                                                    */
  985. /* ------------------------------------------------------------------------------------    */
  986. OSErr SD_Initialize (void) 
  987. /*
  988.     The SD_Initalize message is called when a new job is created.  The standard
  989.     thing to do is to allocate and fill out your globals as you see fit.
  990. */
  991. {
  992.  
  993.     SpecGlobalsHdl     hGlobals;
  994.     OSErr             anErr;
  995.         
  996.     // we make our globals
  997.     hGlobals = (SpecGlobalsHdl) NewHandleClear( sizeof(SpecGlobals) );
  998.     anErr = MemError();
  999.  
  1000.     // and we save them away
  1001.     SetMessageHandlerInstanceContext(hGlobals);
  1002.  
  1003.     // is everything okay?
  1004.     nrequire(anErr, MNewHandleClear);
  1005.     
  1006.     // Don't need to initialize because of the NewHandleCLEAR
  1007.     //(**hGlobals).draftTable = nil;
  1008.     //(**hGlobals).lineFeeds = 0;
  1009.     //(**hGlobals).packagingOptions = kNoPackagingOptions;
  1010.     //(**hGlobals).idleError         = noErr;
  1011.     //(**hGlobals).idleQuery         = false;
  1012.     //(**hGlobals).idleTimeout         = 0;
  1013.     //(**hGlobals).timeoutPending     = false;
  1014.     
  1015.     
  1016.     return(noErr);
  1017.     
  1018.     
  1019. /*-----EXCEPTION HANDLING------*/
  1020.  
  1021.  
  1022. MNewHandleClear:
  1023.     return(anErr);
  1024.     
  1025. } // SD_Initialize
  1026.  
  1027.  
  1028. //<FF>
  1029. /* ------------------------------------------------------------------------------------    */
  1030. OSErr SD_ShutDown(void) 
  1031. /*
  1032.     Shutdown is called when the job is done with.  A good thing to do is to get
  1033.     rid of any additional storage that is laying around.
  1034. */
  1035. {
  1036.     // clean up our stuff
  1037.     SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
  1038.  
  1039.     // get rid of the draft table (if we have one)
  1040.     if (hGlobals)
  1041.         DisposHandle((**hGlobals).draftTable);
  1042.     
  1043.     // we get rid of our storage
  1044.     DisposHandle((Handle) hGlobals);
  1045.     
  1046.     // clear out our globals - to avoid double disposes
  1047.     SetMessageHandlerInstanceContext(nil);
  1048.  
  1049.     return(noErr);
  1050.     
  1051.     
  1052. } // SD_ShutDown
  1053.  
  1054. //<FF>
  1055. /* ------------------------------------------------------------------------------------    */
  1056. OSErr    SD_DefaultPrinter(gxPrinter thePrinter)
  1057. /*
  1058.     This call is made to setup the default printer object.  The job of the
  1059.     specific driver is to add in any viewDevices that it wishes applications
  1060.     to be able to format specifically for.
  1061. */
  1062. {
  1063.     OSErr            anErr;
  1064.     gxViewDevice    vd;
  1065.     gxJob            theJob = GXGetJob();
  1066.     
  1067.     // add the standard viewDevices first
  1068.     anErr = Forward_GXDefaultPrinter(thePrinter);
  1069.     nrequire(anErr, DefaultPrinter);
  1070.     
  1071.     // add a 144 b/w viewDevice
  1072.     vd = NewDeviceResolutionViewDevice();
  1073.     {
  1074.     gxSetColor        theColors[2];
  1075.     gxSetColor        *pColor;
  1076.     gxColorSet        theSet;
  1077.     
  1078.     pColor = &theColors[0];
  1079.     
  1080.     pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0xFFFF;
  1081.     
  1082.     pColor++;
  1083.     pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0x0000;
  1084.     
  1085.     theSet = GXNewColorSet(gxRGBSpace, 2, theColors);
  1086.     SetViewDeviceColorSet(vd, theSet);
  1087.     GXDisposeColorSet(theSet);
  1088.     }
  1089.         
  1090.     anErr = GXAddPrinterViewDevice(thePrinter, vd);
  1091.     nrequire(anErr, FailedAddBWViewDevice);
  1092.  
  1093.     
  1094.     // add a 144 color viewDevice with 8 colors in it
  1095.     //
  1096.     //    Color        Index        R            G            B
  1097.     //    white        0            0xFFFF        0xFFFF        0xFFFF        
  1098.     //    yellow        1            0xFFFF        0xFFFF        0x0000
  1099.     //    magenta        2            0xFFFF        0x0000        0xFFFF
  1100.     //    red            3            0xFFFF        0x0000        0x0000
  1101.     //    cyan        4            0x0000        0xFFFF        0xFFFF
  1102.     //    green        5            0x0000        0xFFFF        0x0000
  1103.     //    blue        6            0x0000        0x0000        0xFFFF
  1104.     //    black        7            0x0000        0x0000        0x0000
  1105.     
  1106.     if (PrinterHasColorRibbon(thePrinter))
  1107.         {
  1108.         gxSetColor        theColors[8];
  1109.         gxSetColor        *pColor;
  1110.         gxColorSet        theSet;
  1111.         short            idx;
  1112.  
  1113.         vd = NewDeviceResolutionViewDevice();
  1114.         
  1115.         pColor = &theColors[0];
  1116.         for (idx = 0; idx < 8; ++idx)
  1117.             {
  1118.             // default the color to black
  1119.             pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0x0000;
  1120.             
  1121.             // and give it componants to go along with this index
  1122.             if (idx & 0x04)
  1123.                 pColor->rgb.red     = 0xFFFF;
  1124.             if (idx & 0x02)
  1125.                 pColor->rgb.green     = 0xFFFF;
  1126.             if (idx & 0x01)
  1127.                 pColor->rgb.blue     = 0xFFFF;
  1128.                 
  1129.             // move on to the next color
  1130.             ++pColor;
  1131.             }
  1132.         
  1133.         theSet = GXNewColorSet(gxRGBSpace, 8, theColors);
  1134.         SetViewDeviceColorSet(vd, theSet);
  1135.         GXDisposeColorSet(theSet);
  1136.  
  1137.         anErr = GXAddPrinterViewDevice(thePrinter, vd);
  1138.         nrequire(anErr, FailedAddColorViewDevice);
  1139.         }
  1140.     
  1141.     /* Only if we are the output printer (not the formatting printer) */
  1142.     if (GXGetJobPrinter(theJob) == GXGetJobOutputPrinter(theJob)) {
  1143.         Collection            jobCollection = GXGetJobCollection(GXGetJob());
  1144.         Handle                 jobQualitySettingsHdl;    
  1145.         gxQualityInfo        *qualitySettings;
  1146.         Ptr                    p;
  1147.         Str255                bestString, roughString;
  1148.  
  1149.         // read in our quality mode strings
  1150.         {
  1151.         short    curResFile = CurResFile();
  1152.         
  1153.         UseResFile(GXGetMessageHandlerResFile());
  1154.         
  1155.         GetIndString( bestString, kNewQualityID, kBestString);
  1156.         GetIndString( roughString, kNewQualityID, kRoughString);
  1157.         UseResFile(curResFile);
  1158.         }
  1159.         
  1160.         jobQualitySettingsHdl = NewHandle(0);
  1161.         anErr = MemError();
  1162.         nrequire(anErr, FailedNewHandle);
  1163.  
  1164.         anErr = GetCollectionItemHdl (     jobCollection,
  1165.                                         gxQualityTag,
  1166.                                         gxPrintingTagID,
  1167.                                         jobQualitySettingsHdl );
  1168.  
  1169.         if (anErr == noErr) 
  1170.             {    /* Check for proper structure -- count as not found if different */
  1171.             HLockHi(jobQualitySettingsHdl);
  1172.  
  1173.             qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
  1174.             p = qualitySettings->qualityNames;
  1175.  
  1176.             if (qualitySettings->disableQuality) 
  1177.                 anErr = collectionItemNotFoundErr;
  1178.             else if (qualitySettings->qualityCount != 2)
  1179.                 anErr = collectionItemNotFoundErr;
  1180.             else if (! IUEqualString((ConstStr255Param)p, bestString))
  1181.                 anErr = collectionItemNotFoundErr;
  1182.             else if (! IUEqualString((ConstStr255Param)(p + p[0] + 1), roughString))
  1183.                 anErr = collectionItemNotFoundErr;
  1184.  
  1185.             HUnlock(jobQualitySettingsHdl);
  1186.             }
  1187.  
  1188.         if (anErr == collectionItemNotFoundErr) 
  1189.             {
  1190.             Size            count;
  1191.  
  1192.             /* Create the proper quality item */
  1193.             SetHandleSize(jobQualitySettingsHdl,(sizeof(gxQualityInfo) + bestString[0] + roughString[0] + 2 ));
  1194.             anErr = MemError();
  1195.             nrequire( anErr, FailedSetHandleSize );
  1196.                 
  1197.             qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
  1198.             
  1199.             qualitySettings->disableQuality = false;
  1200.             qualitySettings->defaultQuality = 1;
  1201.             qualitySettings->currentQuality = 1;
  1202.             qualitySettings->qualityCount = 2;
  1203.  
  1204.             count = bestString[0]+1;
  1205.             p = qualitySettings->qualityNames;
  1206.             BlockMove( bestString, p, count );
  1207.  
  1208.             p += count;
  1209.             BlockMove( roughString, p, roughString[0]+1 );
  1210.  
  1211.             /* Add the proper quality item */
  1212.             anErr = AddCollectionItemHdl (     jobCollection,
  1213.                                             gxQualityTag,
  1214.                                             gxPrintingTagID,
  1215.                                             jobQualitySettingsHdl );
  1216.  
  1217.             /* Make it vilatile by driver */
  1218.             if (anErr == noErr)
  1219.                 (void) SetCollectionItemInfo(jobCollection, gxQualityTag, gxPrintingTagID, 0x0000FFFF, gxVolatileOutputDriverCategory);
  1220.  
  1221.             }
  1222.         
  1223. FailedSetHandleSize:
  1224.         DisposHandle(jobQualitySettingsHdl);
  1225.     }
  1226. FailedNewHandle:
  1227.     return(noErr);
  1228.     
  1229.     
  1230.     
  1231. // EXCEPTION HANDLING
  1232. FailedAddColorViewDevice:
  1233. FailedAddBWViewDevice:
  1234.     GXDisposeViewDevice(vd);
  1235.     
  1236. DefaultPrinter:
  1237.     return(anErr);
  1238.     
  1239. } // SD_DefaultPrinter
  1240.  
  1241. //<FF>
  1242. /* ------------------------------------------------------------------------------------    */
  1243.  
  1244. OSErr SD_DefaultFormat(gxFormat theFormat)
  1245. {
  1246.     OSErr                anErr;
  1247.     Handle                 jobQualitySettingsHdl;    
  1248.     
  1249.     anErr = Forward_GXDefaultFormat(theFormat);
  1250.     
  1251.     // now, if the application has set up a special formatting mode, we need to update
  1252.     // the quality mode collection item (and any private ones we use)
  1253.     if (anErr == noErr)
  1254.         {
  1255.         gxPoint                dpiPoint;
  1256.         gxMapping            vdMapping;
  1257.         gxViewDevice        selectedDevice;
  1258.  
  1259.         dpiPoint.x = ff(72);
  1260.         dpiPoint.x = ff(72);
  1261.         selectedDevice = GXGetPrinterViewDevice(GXGetJobPrinter(GXGetFormatJob(theFormat)), 0);
  1262.         if (selectedDevice != GXGetPrinterViewDevice(GXGetJobPrinter(GXGetFormatJob(theFormat)), 1) )
  1263.             {
  1264.             GXGetViewDeviceMapping(selectedDevice, &vdMapping);
  1265.             MapPoints(&vdMapping, 1, &dpiPoint);
  1266.             
  1267.             {
  1268.             Collection            jobCollection = GXGetJobCollection(GXGetJob());
  1269.             gxQualityInfo        *qualitySettings;
  1270.     
  1271.             jobQualitySettingsHdl = NewHandle(0);
  1272.             anErr = MemError();
  1273.             nrequire(anErr, FailedNewHandle);
  1274.  
  1275.             anErr = GetCollectionItemHdl (     jobCollection,
  1276.                                                 gxQualityTag,
  1277.                                                  gxPrintingTagID,
  1278.                                                jobQualitySettingsHdl );
  1279.  
  1280.             nrequire(anErr, FailedGetCollectionItemHdl);
  1281.  
  1282.             qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
  1283.  
  1284.             qualitySettings->currentQuality = 
  1285.                 (dpiPoint.y > ff(100)) ? (qualitySettings->qualityCount-1) : 0;
  1286.  
  1287.             anErr = AddCollectionItemHdl (     jobCollection,
  1288.                                             gxQualityTag,
  1289.                                             gxPrintingTagID,
  1290.                                             jobQualitySettingsHdl );
  1291.                                                  
  1292.             DisposHandle(jobQualitySettingsHdl);
  1293.             }
  1294.  
  1295.         
  1296.             if (anErr == noErr)
  1297.                 {
  1298.                 long    formatOptions;
  1299.                 
  1300.                 // turn off super-res
  1301.                 formatOptions = 0;
  1302.                 anErr = AddCollectionItem(GXGetFormatCollection(theFormat), 
  1303.                     DriverCreator, 0,
  1304.                     sizeof(formatOptions),
  1305.                     &formatOptions);
  1306.                 }
  1307.             }
  1308.         }
  1309.  
  1310. FailedNewHandle:        
  1311.     return(anErr);
  1312.  
  1313. FailedGetCollectionItemHdl:
  1314.     DisposHandle(jobQualitySettingsHdl);
  1315.     return(anErr);
  1316.     
  1317. } // SD_DefaultFormat
  1318.  
  1319. //<FF>
  1320. /* ------------------------------------------------------------------------------------    */
  1321. OSErr SD_DefaultJob()
  1322. /*
  1323.     We override this message to add our default - highest res possible
  1324. */
  1325. {
  1326.     OSErr    anErr;
  1327.     
  1328.     anErr = Forward_GXDefaultJob();
  1329.     if (anErr == noErr)
  1330.         {
  1331.         long        imagewriterOptions = kSuperRes;
  1332.         
  1333.         anErr = AddCollectionItem(GXGetJobCollection(GXGetJob()), 
  1334.                     DriverCreator,
  1335.                     0,
  1336.                     sizeof(imagewriterOptions),
  1337.                     &imagewriterOptions);
  1338.                     
  1339.         }
  1340.  
  1341.  
  1342.     return(anErr);
  1343.     
  1344. } // SD_DefaultJob
  1345.  
  1346. /* ------------------------------------------------------------------------------------    */
  1347. OSErr SD_OpenConnection(void)
  1348. /*
  1349.     The OpenConnection message is sent in order to open the connection to the device.
  1350. */
  1351. {
  1352.     OSErr    anErr;
  1353.     SpecGlobalsHdl    hGlobals = (SpecGlobalsHdl)GetMessageHandlerInstanceContext();
  1354.     
  1355.     // how to process idle events
  1356.     (**hGlobals).idleError         = noErr;
  1357.     (**hGlobals).idleQuery         = false;
  1358.     (**hGlobals).idleTimeout     = 0;
  1359.     (**hGlobals).timeoutPending = false;
  1360.     
  1361.     // first, open the connection the standard way
  1362.     anErr = Forward_GXOpenConnection();
  1363.     nrequire(anErr, OpenConnection);
  1364.     
  1365.     // then, bring the configuration file up to date
  1366.     anErr = UpdateConfiguration();
  1367.     nrequire(anErr, UpdateConfiguration);
  1368.  
  1369.     return(noErr);
  1370.     
  1371. // EXCEPTION HANDLING
  1372. UpdateConfiguration:
  1373.     GXCleanupOpenConnection();
  1374.     
  1375. OpenConnection:
  1376.  
  1377.     return(anErr);
  1378.     
  1379. } // SD_OpenConnection
  1380.  
  1381. /* ------------------------------------------------------------------------------------    */
  1382. OSErr SD_CloseConnection(void)
  1383. {
  1384.     unsigned short    statusReturn;
  1385.     OSErr            anErr, anErr2;
  1386.     SpecGlobalsHdl    hGlobals = (SpecGlobalsHdl)GetMessageHandlerInstanceContext();
  1387.     ResType            commType = (**hGlobals).commType;
  1388.  
  1389.     if (commType == 'PPTL')
  1390.         {
  1391.         // flush out all data so that we can query the printer properly    one last time
  1392.         anErr = Send_GXWriteData(nil, 0);
  1393.         nrequire(anErr, Send_GXWriteData1);
  1394.         
  1395.         // for PAP: bring the configuration file up to date & check that the printer is online
  1396.         anErr2 = UpdateConfiguration();
  1397.         if (anErr == noErr) anErr = anErr2;
  1398.         }
  1399.     else
  1400.         {
  1401.         // for serial: flush out all data so that we can query the printer properly    one last time
  1402.         anErr = Send_GXWriteData(nil, 0);
  1403.         nrequire(anErr, Send_GXWriteData2);
  1404.  
  1405.         // one last time check up on printer status 
  1406.         if ((**hGlobals).isImageWriterII)
  1407.             {
  1408.             anErr2 = FetchStatusString(&statusReturn, false, true);
  1409.             if (anErr == noErr) anErr = anErr2;
  1410.             }
  1411.         }
  1412.     
  1413. Send_GXWriteData2:
  1414. Send_GXWriteData1:
  1415. FetchStatusString:
  1416.     // close the connection the standard way
  1417.     anErr2 = Forward_GXCloseConnection();
  1418.     if (anErr == noErr) anErr = anErr2;
  1419.         
  1420.     return(anErr);
  1421.     
  1422. } // SD_CloseConnection
  1423.  
  1424. /* ------------------------------------------------------------------------------------    */
  1425. OSErr SD_JobIdle()
  1426. {
  1427.     OSErr            anErr = noErr;
  1428.     SpecGlobalsHdl    hGlobals = (SpecGlobalsHdl)GetMessageHandlerInstanceContext();
  1429.     SpecGlobalsPtr    pGlobals;
  1430.     
  1431.     pGlobals = *hGlobals;
  1432.     if ( (pGlobals->idleQuery) && (pGlobals->commType == 'PPTL') )
  1433.         {
  1434.         unsigned short    statusReturn;
  1435.  
  1436.         pGlobals->idleQuery = false;
  1437.         
  1438.         anErr = FetchStatusString(&statusReturn, true, true);
  1439.         nrequire(anErr, FetchStatusString);
  1440.  
  1441.         anErr = Forward_GXJobIdle();
  1442.  
  1443.         // EXCEPTION HANDLING
  1444.         FetchStatusString:
  1445.             pGlobals = *hGlobals;
  1446.             pGlobals->idleQuery = true;
  1447.         }
  1448.     else    
  1449.         anErr = Forward_GXJobIdle();
  1450.     
  1451.     // if we continue looping here too long during the initial query -- give the user
  1452.     // a chance to bail or correct the problem
  1453.     pGlobals = *hGlobals;
  1454.     if ( (!(pGlobals->timeoutPending)) && (pGlobals->idleTimeout != 0) )
  1455.         {
  1456.         if (TickCount() > pGlobals->idleTimeout)
  1457.             {
  1458.             gxStatusRecord        theStat;
  1459.             gxStatusRecord        *pStat = &theStat;
  1460.             
  1461.             pStat->statusOwner    = 'drvr';
  1462.             pStat->statResId     = kDriverStatus;        
  1463.             pStat->statResIndex = kCheckOnline;            
  1464.             pStat->bufferLen      = 0;
  1465.             pStat->dialogResult = 0;    // ORIGINALLY SET TO ===> nil;
  1466.                         
  1467.             // tell the user to check the printer
  1468.             pGlobals->timeoutPending = true;
  1469.             (void) GXAlertTheUser(pStat);
  1470.             pGlobals = *hGlobals;
  1471.             pGlobals->timeoutPending = false;
  1472.                 
  1473.             // based on the user's response cancel
  1474.             switch (pStat->dialogResult)
  1475.                 {
  1476.                 case ok:
  1477.                     pGlobals->idleTimeout = TickCount() + kQueryTimeout;
  1478.                     break;
  1479.                     
  1480.                 case cancel:
  1481.                     pGlobals->idleError = gxPrUserAbortErr;
  1482.                     break;
  1483.                     
  1484.                 case 3:
  1485.                     pGlobals->idleError = kPutJobOnHoldErr;
  1486.                     break;
  1487.                 }
  1488.  
  1489.             // display "sending data to the printer" message
  1490.             if (anErr == noErr)
  1491.                 anErr = GXReportStatus(kDriverStatus, kSendingData);
  1492.             }
  1493.         }
  1494.         
  1495.     if (anErr == noErr)
  1496.         anErr = pGlobals->idleError;
  1497.         
  1498.     return(anErr);
  1499.     
  1500. } // SD_JobIdle
  1501.  
  1502. /* ------------------------------------------------------------------------------------    */
  1503. OSErr SD_FreeBuffer(gxPrintingBuffer * theBuffer)
  1504. {
  1505.     OSErr            anErr = noErr;
  1506.     OSErr            firstError = noErr;
  1507.     SpecGlobalsHdl    hGlobals = (SpecGlobalsHdl)GetMessageHandlerInstanceContext();
  1508.     
  1509.  
  1510.     if ((**hGlobals).commType == 'PPTL')
  1511.         {
  1512.         unsigned short    statusReturn;
  1513.  
  1514.         anErr = FetchStatusString(&statusReturn, true, true);
  1515.         nrequire(anErr, FetchStatusString);
  1516.         }
  1517.         
  1518.     do
  1519.         {
  1520.         // we can idle query now if we need to    
  1521.         (**hGlobals).idleQuery = true;
  1522.  
  1523.         // try to send the buffer again
  1524.         anErr = Forward_GXFreeBuffer(theBuffer);
  1525.         if (firstError == noErr)
  1526.             firstError = anErr;
  1527.     
  1528.         (**hGlobals).idleQuery = false;
  1529.  
  1530.         // timeout dialog!
  1531.         if (anErr == gxAioTimeout)
  1532.             {
  1533.             gxStatusRecord        theStat;
  1534.             gxStatusRecord        *pStat = &theStat;
  1535.             
  1536.             pStat->statusOwner    = 'drvr';
  1537.             pStat->statResId     = kDriverStatus;        
  1538.             pStat->statResIndex = kCheckOnline;            
  1539.             pStat->bufferLen      = 0;
  1540.             pStat->dialogResult = 0;    // ORIGINALLY SET TO ====> nil;
  1541.                         
  1542.             // tell the user to check the printer
  1543.             (void) GXAlertTheUser(pStat);
  1544.                 
  1545.             // based on the user's response cancel
  1546.             switch (pStat->dialogResult)
  1547.                 {
  1548.                 case ok:
  1549.                     anErr = gxAioTimeout;
  1550.                     break;
  1551.                     
  1552.                 case cancel:
  1553.                     anErr = gxPrUserAbortErr;
  1554.                     break;
  1555.                     
  1556.                 case 3:
  1557.                     anErr = kPutJobOnHoldErr;
  1558.                     break;
  1559.                 }
  1560.             }
  1561.             
  1562.         } while (anErr == gxAioTimeout);
  1563.     
  1564.     // put down the timeout dialog, if we ever put one up
  1565.     if (firstError != noErr)
  1566.         (void) GXReportStatus(kDriverStatus, kSendingData);
  1567.  
  1568.     // error to return from next idle
  1569.     (**hGlobals).idleError = anErr;
  1570.     
  1571. FetchStatusString:        
  1572.     return(anErr);
  1573.     
  1574. } // SD_FreeBuffer
  1575.  
  1576. /* ------------------------------------------------------------------------------------    */
  1577. OSErr SD_DumpBuffer(gxPrintingBuffer * theBuffer)
  1578. {
  1579.     OSErr    anErr;
  1580.     SpecGlobalsHdl    hGlobals = (SpecGlobalsHdl)GetMessageHandlerInstanceContext();
  1581.         
  1582.     if ((**hGlobals).commType == 'PPTL')
  1583.         {
  1584.         unsigned short    statusReturn;
  1585.         anErr = FetchStatusString(&statusReturn, true, true);
  1586.         nrequire(anErr, FetchStatusString);
  1587.         }
  1588.     anErr = Forward_GXDumpBuffer(theBuffer);
  1589.  
  1590. FetchStatusString:        
  1591.     return(anErr);
  1592.     
  1593. } // SD_DumpBuffer
  1594.  
  1595. /* ------------------------------------------------------------------------------------    */
  1596. OSErr SD_StartSendPage(gxFormat pageFormat)
  1597. /*
  1598.     The StartSendPage message is sent just before the page begins to be rendered.
  1599.     
  1600.     Note that the StartSendPage message will not be sent until imaging/communication
  1601.     time, so that user interaction alerts are considered okay here
  1602. */
  1603. {
  1604.     OSErr                        anErr = noErr;
  1605.     gxJob                        theJob = GXGetJob();
  1606.     Collection                    jobCollection;
  1607.     gxPaperType                    thePaperType;
  1608.     gxTrayFeedInfo                trayFeedInfo;
  1609.     long                        itemSize = sizeof(trayFeedInfo);
  1610.     ResType                        commType;
  1611.     unsigned short                statusReturn;
  1612.     
  1613.     jobCollection = GXGetJobCollection(theJob);
  1614.     
  1615.     // cache communications type
  1616.     commType = (**(SpecGlobalsHdl)GetMessageHandlerInstanceContext()).commType;
  1617.     if (commType == 'PPTL')
  1618.         {
  1619.         anErr = FetchStatusString(&statusReturn, true, true);
  1620.         nrequire(anErr, FetchStatusString);
  1621.         }
  1622.     else
  1623.         statusReturn = 0;
  1624.         
  1625.     // check to see if this particular page is to be manually fed
  1626.     anErr = GetCollectionItem(jobCollection, gxTrayFeedTag, gxPrintingTagID, &itemSize, &trayFeedInfo);
  1627.     nrequire(anErr, FailedGetCollectionItem);
  1628.             
  1629.     // manual feed or out of paper?  Time to ask the user what to do
  1630.     if     (     trayFeedInfo.manualFeedThisPage
  1631.         ||  ( ( (statusReturn & kOutOfPaperMask) != 0 ) )
  1632.         )
  1633.         {
  1634.         // Wait for all IO to complete, so that we can correctly tell the user what to do.
  1635.         // Since the WriteData message makes sure all data is flushed before performing the
  1636.         // IO, this call insures that pending IO is complete.
  1637.         anErr = Send_GXWriteData(nil, 0);
  1638.         nrequire(anErr, FlushAllData);
  1639.  
  1640.  
  1641.         // then, conduct the alert with the user
  1642.         {
  1643.         gxStatusRecord        *pStat;
  1644.         
  1645.         // make a status record containing the request to the user - note that 
  1646.         // we have to make room for ManualFeedRecord OR OutOfPaperRecord, but manual is bigger
  1647.         pStat = (gxStatusRecord *)NewPtrClear(sizeof(gxStatusRecord)  + sizeof(gxManualFeedRecord));
  1648.         anErr = MemError();
  1649.         nrequire(anErr, NewPtrClear);
  1650.                 
  1651.         pStat->statusOwner    = 'univ';
  1652.         pStat->statResId     = gxUnivAlertStatusResourceId;    // we use the built-in status for this
  1653.         pStat->dialogResult = 0;    // ORIGINALLY SET TO =====> nil;
  1654.         
  1655.         if (trayFeedInfo.manualFeedThisPage)
  1656.             {
  1657.             gxManualFeedRecord    *pFeed;
  1658.             
  1659.             pStat->statResIndex = gxUnivManualFeedIndex;            // status meaning "manual feed alert"
  1660.             pStat->bufferLen      = sizeof(gxManualFeedRecord);
  1661.             pFeed = (gxManualFeedRecord*)&pStat->statusBuffer;
  1662.         
  1663.             // we can switch to autofeed if we want - and tell the user what kind of paper to load in
  1664.             pFeed->canAutoFeed = true;
  1665.             GXGetPaperTypeName(thePaperType = GXGetFormatPaperType(pageFormat), pFeed->paperTypeName);
  1666.             }
  1667.         else
  1668.             {
  1669.             gxOutOfPaperRecord    *pOut;
  1670.             
  1671.             pStat->statResIndex = gxUnivOutOfPaperIndex;            // status meaning "manual feed alert"
  1672.             pStat->bufferLen      = sizeof(gxOutOfPaperRecord);
  1673.             
  1674.             pOut = (gxOutOfPaperRecord*)&pStat->statusBuffer;
  1675.             GXGetPaperTypeName(GXGetFormatPaperType(pageFormat), pOut->paperTypeName);
  1676.             }
  1677.             
  1678.         // keep sending the user the alert until either
  1679.         //  a) the problem resolves itself
  1680.         //  b) the user responds via the dialog
  1681.         //  c) some other (fatal) error happens
  1682.         do
  1683.             {
  1684.             
  1685.             // tell the user
  1686.             anErr = GXAlertTheUser(pStat);
  1687.             
  1688.             // if the paper got suddenly loaded, do an OK
  1689.             if (commType == 'PPTL')
  1690.                 {
  1691.                 (void) FetchStatusString(&statusReturn, true, true);
  1692.                 if ((statusReturn & kOutOfPaperMask) == 0)
  1693.                     {
  1694.                     pStat->dialogResult = ok;
  1695.                     anErr = noErr;
  1696.                     }
  1697.                 }
  1698.                 
  1699.             } while ((anErr == noErr) && (pStat->dialogResult == 0));    // ORIGINALLY SET TO ==> (pStat->dialogResult == nil)
  1700.  
  1701.         // based on the user's response, continue, cancel, or switch to auto feed
  1702.         switch ( pStat->dialogResult )
  1703.             {
  1704.             case ok:
  1705.                 // paper is loaded
  1706.                 break;
  1707.                 
  1708.             case cancel:
  1709.                 // user wishes to stop the printing process
  1710.                 anErr = gxPrUserAbortErr;
  1711.                 break;
  1712.                 
  1713.             case gxAutoFeedButtonId:
  1714.                 // do rest of job with auto feed
  1715.                 
  1716.                 {
  1717.                 gxPaperFeedInfo paperFeed;
  1718.                 
  1719.                 /* Update for job */
  1720.                 paperFeed.autoFeed = true;
  1721.                 (void) AddCollectionItem(jobCollection, gxPaperFeedTag, gxPrintingTagID, sizeof(paperFeed), &paperFeed);
  1722.                 }
  1723.                 
  1724.                 /* Update as it may be reused */
  1725.                 trayFeedInfo.manualFeedThisPage = false;    /* Other trayInfo fields are still valid */
  1726.                 (void) AddCollectionItem(jobCollection, gxTrayFeedTag, gxPrintingTagID, sizeof(trayFeedInfo), &trayFeedInfo);
  1727.                 
  1728.                 /* Can pass paper type reference as this IS device communication time */
  1729.                 anErr = Send_GXCheckStatus((Ptr) &thePaperType, sizeof(thePaperType), 0, 'univ');
  1730.                 
  1731.                 /* No need to reset tray from gxTrayFeedInfo.feedTrayIndex as there is only one tray! */
  1732.                 break;
  1733.                 
  1734.             } // switch
  1735.             
  1736.             
  1737.         // done with the status now
  1738.         DisposPtr((Ptr) pStat);
  1739.         }
  1740.             
  1741.         } // if manual feed job
  1742.         
  1743.     // display "sending data to the printer" message
  1744.     if (anErr == noErr)
  1745.         anErr = GXReportStatus(kDriverStatus, kSendingData);
  1746.         
  1747.     nrequire(anErr, FailedWaitForPaper);
  1748.  
  1749.     // continue with the standard starting of the page
  1750.     anErr = Forward_GXStartSendPage(pageFormat);
  1751.         
  1752.         
  1753. // FALL THROUGH AND HANDLE EXCEPTIONS
  1754.  
  1755. FailedWaitForPaper:
  1756. NewPtrClear:
  1757. FlushAllData:
  1758. FailedGetCollectionItem:
  1759. FetchStatusString:
  1760.     return(anErr);
  1761.     
  1762. } // SD_StartSendPage
  1763.  
  1764. /* ------------------------------------------------------------------------------------    */
  1765. OSErr SD_FinishSendPage()
  1766. {
  1767.     OSErr        anErr = noErr;
  1768.     Str63        formLength;            // should be more than big enough for form skipping
  1769.     char        len = 0;
  1770.  
  1771.     // we may have issued line feeds RIGHT up to the end of the page.  If
  1772.     // we do that and then issue a form feed, we'll kick out a blank page.
  1773.     // to avoid that, we back up a tad and then let the normal form feed
  1774.     // go through.  Option 2 would be to track each and every motion control
  1775.     // we send to the printer -- but that's more work than this.  In addition,
  1776.     // this method makes sure we are synced up exactly to the hardware
  1777.     formLength[len++] = ESCAPE;
  1778.     formLength[len++] = 'T';
  1779.     formLength[len++] = '0';
  1780.     formLength[len++] = '1';
  1781.     formLength[len++] = ESCAPE;
  1782.     formLength[len++] = 'r';
  1783.     formLength[len++] = 0x0A;
  1784.     
  1785.     // reset to forward motion for the form feed
  1786.     formLength[len++] = ESCAPE;
  1787.     formLength[len++] = 'f';
  1788.     
  1789.     anErr = Send_GXBufferData((char*)&formLength[0], len, gxNoBufferOptions );
  1790.     nrequire(anErr, Send_GXBufferData);
  1791.     
  1792.     // Default implementation provides the actual form feed
  1793.     anErr = Forward_GXFinishSendPage();
  1794.  
  1795. // FALL THROUGH EXCEPTION HANDLING
  1796. Send_GXBufferData:
  1797.  
  1798.     return(anErr);
  1799.     
  1800. } // SD_FinishSendPage
  1801.  
  1802. /* ------------------------------------------------------------------------------------    */
  1803. OSErr SD_JobFormatDialog(gxDialogResult*    theResult)
  1804. /*
  1805.     This message is sent in response to the user's request to put up a formatting dialog
  1806. */
  1807. {
  1808.     OSErr                     anErr;
  1809.     gxJobFormatModeTableHdl    theJobFormatModeList;
  1810.     long                    i;
  1811.     gxJob                     theJob = GXGetJob();
  1812.     
  1813.     // set up the JobFormatMode information
  1814.     
  1815.     anErr = GXGetAvailableJobFormatModes(&theJobFormatModeList);
  1816.     if ((!anErr) && (theJobFormatModeList))
  1817.         {
  1818.         for (i = 0; i <= (*theJobFormatModeList)->numModes - 1; ++i) 
  1819.             {
  1820.             if ((*theJobFormatModeList)->modes[i] == gxTextJobFormatMode) 
  1821.                 {
  1822.                 GXSetPreferredJobFormatMode(gxTextJobFormatMode, false);
  1823.                 break;
  1824.                 }
  1825.             }
  1826.         DisposHandle((Handle)theJobFormatModeList);
  1827.         }
  1828.         
  1829.     // do the normal dialogs after handling the job format mode stuff
  1830.     return(Forward_GXJobDefaultFormatDialog(theResult));
  1831.     
  1832. } // SD_JobFormatModeQuery
  1833.  
  1834. /* ------------------------------------------------------------------------------------    */
  1835. OSErr SD_JobFormatModeQuery(    gxQueryType        theQuery,
  1836.                                 void*            srcData,
  1837.                                 void*            dstData)
  1838. /*
  1839.     This message is sent to find out information about the current job format mode.
  1840. */
  1841. {
  1842.     OSErr        anErr = noErr;
  1843.     Handle        theFonts;
  1844.     Handle        theStyles;
  1845.     
  1846.     // What type of query is being requested?
  1847.     switch(theQuery) 
  1848.     {
  1849.         case gxSetStyleJobFormatCommonStyleQuery:
  1850.         {
  1851.             char                *pStyleName;
  1852.  
  1853.             // Fetch the list of supported styles
  1854.             
  1855.             anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeStylesID, &theStyles);
  1856.             require(anErr == noErr, FailedToLoadStyles1);
  1857.             
  1858.             HNoPurge(theStyles);
  1859.             HLock(theStyles);
  1860.             
  1861.             // Determine which style is being referenced and set the corresponding style (only 2 styles
  1862.             // are currently supported)
  1863.             
  1864.             if (**((short **) theStyles) == 2)    //    T => We have the correct number of styles
  1865.             {
  1866.                 char        whichFace = 0;
  1867.                 
  1868.                 pStyleName = ((char *) *theStyles) + sizeof(short); 
  1869.                 
  1870.                 if ( IUCompString((ConstStr255Param)pStyleName, (ConstStr255Param)srcData) == 0 )    //    T => They want bold face
  1871.                 {
  1872.                     whichFace = bold;
  1873.                 }
  1874.                 else
  1875.                 {
  1876.                     // Point to the next name in the list
  1877.                     pStyleName += *pStyleName + 1;
  1878.  
  1879.                     if ( IUCompString((ConstStr255Param)pStyleName, (ConstStr255Param)srcData) == 0 )    //    T => They want underline face
  1880.                     {
  1881.                         whichFace = underline;
  1882.                     }
  1883.                 }
  1884.  
  1885.                 //    If the client specified a valid face, set it now
  1886.                 if (whichFace != 0)
  1887.                 {
  1888.                     SetStyleCommonFace((gxStyle) dstData, GetStyleCommonFace((gxStyle) dstData) | whichFace);
  1889.                 }
  1890.             }
  1891.             // else - something is wrong with our resource
  1892.             
  1893.             // Dump the temporary handle
  1894.             DisposHandle(theStyles);
  1895.             
  1896.             break;
  1897.         }
  1898.             
  1899.         case gxGetJobFormatFontCommonStylesQuery:
  1900.         {
  1901.             short                numStyles;
  1902.             short                i;
  1903.             char                *pStyleName;
  1904.  
  1905.             // Fetch the list of supported styles
  1906.             
  1907.             anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeStylesID, &theStyles);
  1908.             require(anErr == noErr, FailedToLoadStyles2);
  1909.             
  1910.             HNoPurge(theStyles);
  1911.             HLock(theStyles);
  1912.             
  1913.             // Determine the number of styles in the list
  1914.             numStyles = **((short **) theStyles);
  1915.  
  1916.             if (*(Handle *)dstData != nil)    //    T => Resize the handle to hold info. on the styles
  1917.                 SetHandleSize(*(Handle *)dstData, sizeof(gxStyleNameTable) + ((numStyles - 1) * sizeof(Str255)));
  1918.             else
  1919.                 *(Handle *)dstData = NewHandle(sizeof(gxStyleNameTable) + ((numStyles - 1) * sizeof(Str255)));
  1920.             
  1921.             anErr = MemError();
  1922.             require(anErr == noErr, StyleTableResizeFailed);
  1923.             
  1924.             // Now extract the name of each of the supported fonts
  1925.             
  1926.             for (i = 1, pStyleName = ((char *) *theStyles) + sizeof(short); i <= numStyles; ++i, pStyleName += *pStyleName + 1)
  1927.             {
  1928.                 BlockMove(pStyleName, (*((gxStyleNameTableHdl) *(Handle *)dstData))->styleNames[i - 1], *pStyleName + 1);
  1929.             }
  1930.             
  1931.             (*((gxStyleNameTableHdl) *(Handle *)dstData))->numStyleNames = numStyles;
  1932.             
  1933.             // Dump the temporary handle
  1934.             DisposHandle(theStyles);
  1935.             
  1936.             break;
  1937.         }
  1938.             
  1939.         case gxGetJobFormatLineConstraintQuery:            //    This type of query is not supported
  1940.             if (*(Handle *)dstData != nil)
  1941.                 SetHandleSize(*(Handle *)dstData, 0);        // Don't return any data
  1942.             break;
  1943.             
  1944.         case gxGetJobFormatFontsQuery:
  1945.         {
  1946.             short                numFonts;
  1947.             short                i;
  1948.             char                *pFontName;
  1949.  
  1950.             // Fetch the list of supported fonts
  1951.             
  1952.             anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeFontsID, &theFonts);
  1953.             require(anErr == noErr, FailedToLoadFonts);
  1954.             
  1955.             HNoPurge(theFonts);
  1956.             HLock(theFonts);
  1957.             
  1958.             // Determine the number of fonts in the list
  1959.             numFonts = **((short **) theFonts);
  1960.  
  1961.             if (*(Handle *)dstData != nil)    //    T => Resize the handle to hold info. on the fonts
  1962.                 SetHandleSize(*(Handle *)dstData, sizeof(gxFontTable) + ((numFonts - 1) * sizeof(gxFont)));
  1963.             else
  1964.                 *(Handle *)dstData = NewHandle(sizeof(gxFontTable) + ((numFonts - 1) * sizeof(gxFont)));
  1965.             
  1966.             anErr = MemError();
  1967.             require(anErr == noErr, FontTableResizeFailed);
  1968.             
  1969.             // Now generate a reference to each of the supported fonts
  1970.             
  1971.             for (i = 1, pFontName = ((char *) *theFonts) + sizeof(short); i <= numFonts; ++i, pFontName += *pFontName + 1)
  1972.             {
  1973.                 gxFont            thisFont;
  1974.                 gxFontTable        *pFontTable;
  1975.             
  1976.                 //     ORIGINAL CODE
  1977.                 //    thisFont = FindPNameFont(gxFullFontName, (ConstStr255Param)pFontName);
  1978.                 // END OF ORIGINAL CODE
  1979.                 
  1980.                 // CODE ADDED IN FROM GX FONTLIBRARY.C AS THINK C WON'T COMPILE LIBRARY
  1981.  
  1982.                 GXFindFonts(0, gxFullFontName,
  1983.                             gxMacintoshPlatform,
  1984.                             gxRomanScript,
  1985.                             gxEnglishLanguage,
  1986.                             pFontName[0], (ConstStr255Param)pFontName, 1, 1, &thisFont);
  1987.     
  1988.                 // ENDCODE ADDED IN FROM LIBRARY
  1989.                 
  1990.                 pFontTable = *((gxFontTableHdl) *(Handle *)dstData);
  1991.                 pFontTable->fonts[i - 1] = thisFont;
  1992.             }
  1993.             
  1994.             (*((gxFontTableHdl) *(Handle *)dstData))->numFonts = numFonts;
  1995.             
  1996.             // Dump the temporary handle
  1997.             DisposHandle(theFonts);
  1998.  
  1999.             break;
  2000.         }
  2001.             
  2002.         case gxGetJobFormatFontConstraintQuery:
  2003.         {
  2004.             gxPositionConstraintTable        *pPositionTable;
  2005.             
  2006.             if ( *(Handle *)dstData != nil)    //    T => Resize the handle to hold info. on position constraints
  2007.                 SetHandleSize(*(Handle *)dstData, sizeof(gxPositionConstraintTable) + sizeof(Fixed));
  2008.             else
  2009.                 *(Handle *)dstData = NewHandle( sizeof(gxPositionConstraintTable) + sizeof(Fixed) );
  2010.             
  2011.             pPositionTable = *((gxPositionConstraintTableHdl) *(Handle *)dstData);
  2012.             
  2013.             pPositionTable->phase.x     = 0;                //    Start at the top left corner of the page
  2014.             pPositionTable->phase.y     = 0;
  2015.             pPositionTable->offset.x     = ff(12);        // Indent from the top left by a six lines per inch margin
  2016.             pPositionTable->offset.y     = ff(12);         
  2017.             pPositionTable->numSizes     = 2;                // Two font sizes supported
  2018.             pPositionTable->sizes[0]     = ff(10);         // 10 pitch
  2019.             pPositionTable->sizes[1]     = ff(12);         // 12 pitch
  2020.             
  2021.             break;
  2022.         }
  2023.     } // switch
  2024.     
  2025.     return(anErr);
  2026.     
  2027.  
  2028. /******* Clean-up *******/
  2029.  
  2030. StyleTableResizeFailed:
  2031.     DisposHandle((Handle) theStyles);
  2032.     return(anErr);
  2033.  
  2034. FontTableResizeFailed:
  2035.     DisposHandle((Handle) theFonts);
  2036.  
  2037. FailedToLoadStyles1:
  2038. FailedToLoadStyles2:
  2039. FailedToLoadFonts:
  2040.     return(anErr);
  2041.     
  2042. } // SD_JobFormatModeQuery
  2043.  
  2044. //<FF>
  2045. /* ------------------------------------------------------------------------------------    */
  2046. OSErr SD_SetupImageData(
  2047.     gxRasterImageDataHdl hImageData)        // raster image data stuff
  2048. /*
  2049.     This message is called to setup the constant data used for imaging the entire job.
  2050. */
  2051. {
  2052.  
  2053.     SpecGlobalsHdl                 hGlobals = GetMessageHandlerInstanceContext();
  2054.     OSErr                        anErr;
  2055.     gxRasterImageDataPtr        pImageData;
  2056.     Boolean                     isJobNotFinalQuality;
  2057.     Boolean                     isTextJobFormatMode;
  2058.     long                        imagewriterOptions;
  2059.     short                       count;
  2060.     Handle                      draftTable;
  2061.     
  2062.     CMYKRenderCollection planes;
  2063.     long                 itemSize = sizeof(CMYKRenderCollection);
  2064.     Collection           jobCollection;
  2065.     gxJob                 theJob;
  2066.     
  2067.     gxSetColor            theColors[9];
  2068.     gxColorSet            theSet;
  2069.     short                idx;
  2070.     gxPlaneSetupRec     *pOnePlane;
  2071.  
  2072. // do the default setup
  2073.     anErr = Forward_GXSetupImageData(hImageData);
  2074.     nrequire(anErr, Forward_GXSetupImageData);
  2075.     
  2076. // test for 'final' quality mode
  2077.     isJobNotFinalQuality = !JobIsBest(&imagewriterOptions);
  2078.     
  2079. // test for textJobFormatMode
  2080.     isTextJobFormatMode = ( GXGetJobFormatMode( GXGetJob() ) == gxTextJobFormatMode);
  2081.             
  2082. // if the job is not final quality or using textJobFormatMode,
  2083. //               downgrade the imaging data to our lower quality
  2084.     if (isJobNotFinalQuality  ||  isTextJobFormatMode)
  2085.     {
  2086. //
  2087. // ROUGH OR TEXT MODE
  2088. //        
  2089.  
  2090.     // dereference for size and speed    
  2091.         pImageData = *hImageData;
  2092.                 
  2093.     // image at 80 or 72 dpi
  2094.         if (imagewriterOptions & kSuperRes)
  2095.             pImageData->hImageRes = ff(80);
  2096.         else
  2097.             pImageData->hImageRes = ff(72);
  2098.         pImageData->vImageRes = ff(72);
  2099.         
  2100.     // textJobFormatMode loads up the draft table, else setup halftones
  2101.         if (isTextJobFormatMode)
  2102.         {
  2103.  
  2104.             anErr = Send_GXFetchTaggedDriverData('idft', gxPrintingDriverBaseID, &draftTable);
  2105.             nrequire(anErr, FailedToLoadDraftTable);
  2106.             
  2107.         // store away the draft table
  2108.             (**hGlobals).draftTable = draftTable;
  2109.  
  2110.         // Download something?    
  2111.             anErr = Send_GXFetchTaggedDriverData('idft', gxPrintingDriverBaseID+1, &draftTable);
  2112.             if (anErr == resNotFound)
  2113.             {
  2114.                 draftTable = nil;
  2115.                 anErr = noErr;
  2116.             }
  2117.             nrequire(anErr, GetDownloadTable);    
  2118.         
  2119.             if (draftTable)
  2120.             {
  2121.                 HLock(draftTable);
  2122.                 anErr = Send_GXBufferData(*draftTable, GetHandleSize(draftTable), gxDontSplitBuffer);
  2123.                 DisposHandle(draftTable);
  2124.                 nrequire(anErr, SendDownloadTable);
  2125.             }
  2126.         }
  2127.         else
  2128.         {            
  2129.     // use dither level that will look better at 72 dpi 
  2130.     // resolution than our default values (MAYBE: 4 is the default now anyway)
  2131.             pImageData->theSetup.planeSetup[0].planeHalftone.method = 4;
  2132.             
  2133.     // of course, turn off color matching when in non-final mode!
  2134.             pImageData->theSetup.planeSetup[0].planeProfile = nil;
  2135.         }
  2136.             
  2137.         if (isJobNotFinalQuality)
  2138.         {
  2139.             if (imagewriterOptions & kSuperRes)
  2140.             {
  2141.         // use bidirectional instead of unidirectional
  2142.         // and also <esc>N instead of <esc>p for quality mode
  2143.  
  2144.                 pImageData->packageControls.startPageStringID = gxPrintingDriverBaseID+3;
  2145.             }
  2146.             else
  2147.             {
  2148.         // use bidirectional instead of unidirectional
  2149.         // and also <esc>n instead of <esc>p for quality mode
  2150.         
  2151.                 pImageData->packageControls.startPageStringID = gxPrintingDriverBaseID+2;
  2152.             }
  2153.         }
  2154.         
  2155.     // packaging data
  2156.         pImageData->packagingInfo.headHeight         = 8;        // 8 pins (instead of 16)
  2157.         pImageData->packagingInfo.numberPasses         = 1;        // in 1 head pass (instead of 2)
  2158.         pImageData->packagingInfo.passOffset         = 0;        // with no space between passes
  2159.     }
  2160.     else
  2161.     {
  2162. //
  2163. // FINAL QUALITY
  2164. //
  2165.  
  2166.     // dereference for size and speed    
  2167.         pImageData = *hImageData;
  2168.                 
  2169.     // image at 160 or 144 dpi
  2170.         if (imagewriterOptions & kSuperRes)
  2171.         {
  2172.             pImageData->hImageRes = ff(160);
  2173.             pImageData->packageControls.startPageStringID = gxPrintingDriverBaseID+1;
  2174.         }
  2175.         else
  2176.         {
  2177.             pImageData->hImageRes = ff(144);
  2178.             pImageData->packageControls.startPageStringID = gxPrintingDriverBaseID+0;
  2179.         }
  2180.     }
  2181.     
  2182. // not a color ribbon?  Setup for black and white - do a B/W halftone rather than a dither
  2183.     if (!PrinterHasColorRibbon(GXGetJobOutputPrinter(GXGetJob())))
  2184.     {
  2185. // dereference for size and speed    
  2186.         pImageData = *hImageData;
  2187.  
  2188. // one plane, no color flags, move the halftone info up into correct position
  2189.         pImageData->theSetup.planes = 1;
  2190.         pImageData->theSetup.depth = 1;
  2191.         pImageData->packagingInfo.colorPasses = 1;
  2192.         pImageData->packagingInfo.packageOptions = 0;
  2193.         pImageData->theSetup.planeSetup[0].planeSpace = gxNoSpace;
  2194.         pImageData->theSetup.planeSetup[0].planeSet = nil;
  2195.         pImageData->theSetup.planeSetup[0].planeProfile = nil;
  2196.         pImageData->theSetup.planeSetup[0].planeOptions = gxDefaultOffscreen;
  2197.         pImageData->theSetup.planeSetup[0].planeHalftone.method = gxRoundDot;
  2198.         pImageData->theSetup.planeSetup[0].planeHalftone.tintSpace = gxRGBSpace;
  2199.     }
  2200.     else
  2201.     {
  2202. // It has a color ribon, so if it has a render options collection, then set up the options
  2203. // approriately.
  2204.  
  2205. // First, see if the job has render options
  2206.  
  2207.         theJob = GXGetJob();
  2208.  
  2209.         jobCollection = GXGetJobCollection(theJob);
  2210.  
  2211.         if (!GetCollectionItem( jobCollection, 
  2212.                                 kCMYKRenderCollectionType, kCMYKRenderCollectionID, 
  2213.                                 &itemSize, &planes))
  2214.         {
  2215.  
  2216.             pImageData = *hImageData;                
  2217.     
  2218.             if (planes.renderMode == kDitherIt)
  2219.             {
  2220. //
  2221. // Dither setup
  2222. //
  2223.     // Create a color set
  2224.                 for (idx = 0; idx < 9; ++idx)
  2225.                     {
  2226.                 // default the color to black
  2227.                     theColors[idx].rgba.red
  2228.                         = theColors[idx].rgba.green
  2229.                         = theColors[idx].rgba.blue
  2230.                         = theColors[idx].rgba.alpha = 0x0000;
  2231.                     
  2232.                 // and give it componants to go along with this index
  2233.                     if (   (idx == 0)
  2234.                         || (idx == 1)
  2235.                         || (idx == 2)
  2236.                         || (idx == 3)
  2237.                         || (idx == 7))
  2238.                         theColors[idx].rgba.red     = 0xFFFF;
  2239.                     if (   (idx == 0)
  2240.                         || (idx == 1)
  2241.                         || (idx == 4)
  2242.                         || (idx == 5)
  2243.                         || (idx == 7))
  2244.                         theColors[idx].rgba.green     = 0xFFFF;
  2245.                     if (   (idx == 0)
  2246.                         || (idx == 2)
  2247.                         || (idx == 4)
  2248.                         || (idx == 6)
  2249.                         || (idx == 7))
  2250.                         theColors[idx].rgba.blue     = 0xFFFF;
  2251.                         
  2252.                     }
  2253.  
  2254.                 theSet = GXNewColorSet(gxRGBSpace, 9, theColors);
  2255.  
  2256. // Step through each plane, setting up the appropriate values
  2257.                 for (count = 0; count < 4; ++count)
  2258.                 {
  2259.         // dereference for size and speed            
  2260.                     pOnePlane = &(pImageData->theSetup.planeSetup[count]);
  2261.                     
  2262.         // Set up the options for dithering
  2263.                     pOnePlane->planeOptions = gxDontSetHalftone + gxDotTypeIsDitherLevel;
  2264.  
  2265.         // Angle and frequency are not used when dithering
  2266.                     pOnePlane->planeHalftone.angle     = 0;
  2267.                     pOnePlane->planeHalftone.frequency = 0;
  2268.                     
  2269.         // When the planeOption's gxDotTypeIsDitherLevel flag is set, then planeHalftone.method
  2270.         // is used for the dither level
  2271.         
  2272.                     pOnePlane->planeHalftone.method  = planes.ditherLevel;
  2273.         
  2274.         // Set default for luminance
  2275.                     pOnePlane->planeHalftone.tinting = gxLuminanceTint;
  2276.     
  2277.         // Set up the dot color
  2278.                     pOnePlane->planeHalftone.dotColor.space              = gxRGBSpace;
  2279.                     pOnePlane->planeHalftone.dotColor.profile            = nil;
  2280.                 
  2281.                 // default each plane to 0
  2282.                     pOnePlane->planeHalftone.dotColor.element.rgba.red
  2283.                             = pOnePlane->planeHalftone.dotColor.element.rgba.green
  2284.                             = pOnePlane->planeHalftone.dotColor.element.rgba.blue
  2285.                             = pOnePlane->planeHalftone.dotColor.element.rgba.alpha
  2286.                             = 0;
  2287.  
  2288.                     if (   (count == 0)
  2289.                         || (count == 1))
  2290.                         pOnePlane->planeHalftone.dotColor.element.rgba.red   = 0xFFFF;
  2291.                     if (   (count == 0)
  2292.                         || (count == 2))
  2293.                         pOnePlane->planeHalftone.dotColor.element.rgba.green   = 0xFFFF;
  2294.                     if (   (count == 2)
  2295.                         || (count == 3))
  2296.                         pOnePlane->planeHalftone.dotColor.element.rgba.blue   = 0xFFFF;
  2297.     
  2298.         // Set up the background dot color
  2299.                     pOnePlane->planeHalftone.backgroundColor.space              = gxRGBSpace;
  2300.                     pOnePlane->planeHalftone.backgroundColor.profile            = nil;
  2301.                     pOnePlane->planeHalftone.backgroundColor.element.rgba.red
  2302.                         = pOnePlane->planeHalftone.backgroundColor.element.rgba.green
  2303.                         = pOnePlane->planeHalftone.backgroundColor.element.rgba.blue
  2304.                         = pOnePlane->planeHalftone.backgroundColor.element.rgba.alpha
  2305.                         = 0xFFFF;
  2306.     
  2307.         // Set up for an RGB tint space
  2308.                     pOnePlane->planeHalftone.tintSpace = gxRGBSpace;
  2309.  
  2310.         // And an indexed plane space
  2311.                     pOnePlane->planeSpace    = gxIndexedSpace;
  2312.  
  2313.         // Set up the plane to the same as the one we just created
  2314.                     pOnePlane->planeSet     = theSet;
  2315.  
  2316.         // no color profile so set to nil
  2317.                     pOnePlane->planeProfile = nil;
  2318.                 }
  2319.             }
  2320.             else
  2321.             {
  2322. //
  2323. // Half-Tone setup
  2324. //
  2325.                 for (count = 0; count < 4; ++count)
  2326.                 {
  2327.         // dereference for size and speed            
  2328.                     pOnePlane = &(pImageData->theSetup.planeSetup[count]);
  2329.     
  2330.         // Set up the options for halftonning...gxDefaultOffscreen
  2331.                     pOnePlane->planeOptions = gxDefaultOffscreen;
  2332.  
  2333.         // Set this dot type from the collection
  2334.                     pOnePlane->planeHalftone.method    = planes.dotType;
  2335.  
  2336.         // Set this planes angle and frequency from the collection
  2337.         // and the appropriate tint for this plane
  2338.                     switch (count+1) {
  2339.                         case (kYellowPass) : 
  2340.                             pOnePlane->planeHalftone.angle     = planes.angles   [kRenderOptsYellow];
  2341.                             pOnePlane->planeHalftone.frequency = planes.frequency[kRenderOptsYellow];
  2342.                             pOnePlane->planeHalftone.tinting   = gxComponent3Tint;
  2343.                             break;
  2344.                         case (kMagentaPass) : 
  2345.                             pOnePlane->planeHalftone.angle     = planes.angles   [kRenderOptsMagenta];
  2346.                             pOnePlane->planeHalftone.frequency = planes.frequency[kRenderOptsMagenta];
  2347.                             pOnePlane->planeHalftone.tinting   = gxComponent2Tint;
  2348.                             break;
  2349.                         case (kCyanPass) : 
  2350.                             pOnePlane->planeHalftone.angle     = planes.angles   [kRenderOptsCyan];
  2351.                             pOnePlane->planeHalftone.frequency = planes.frequency[kRenderOptsCyan];
  2352.                             pOnePlane->planeHalftone.tinting   = gxComponent1Tint;
  2353.                             break;
  2354.                         case (kBlackPass) : 
  2355.                             pOnePlane->planeHalftone.angle     = planes.angles   [kRenderOptsBlack];
  2356.                             pOnePlane->planeHalftone.frequency = planes.frequency[kRenderOptsBlack];
  2357.                             pOnePlane->planeHalftone.tinting   = gxComponent4Tint;
  2358.                             break;
  2359.                     }
  2360.  
  2361.  
  2362.         // Set up the dot color to black
  2363.                     pOnePlane->planeHalftone.dotColor.space              = gxRGBSpace;
  2364.                     pOnePlane->planeHalftone.dotColor.profile            = nil;
  2365.                     pOnePlane->planeHalftone.dotColor.element.rgba.red
  2366.                         = pOnePlane->planeHalftone.dotColor.element.rgba.green
  2367.                         = pOnePlane->planeHalftone.dotColor.element.rgba.blue
  2368.                         = pOnePlane->planeHalftone.dotColor.element.rgba.alpha
  2369.                         = 0;
  2370.     
  2371.         // Set up the background dot color to white
  2372.                     pOnePlane->planeHalftone.backgroundColor.space              = gxRGBSpace;
  2373.                     pOnePlane->planeHalftone.backgroundColor.profile            = nil;
  2374.                     pOnePlane->planeHalftone.backgroundColor.element.rgba.red
  2375.                         = pOnePlane->planeHalftone.backgroundColor.element.rgba.green
  2376.                         = pOnePlane->planeHalftone.backgroundColor.element.rgba.blue
  2377.                         = pOnePlane->planeHalftone.backgroundColor.element.rgba.alpha
  2378.                         = 0xFFFF;
  2379.     
  2380.         // Set up for an CMYK tint space
  2381.                     pOnePlane->planeHalftone.tintSpace = gxCMYKSpace;
  2382.  
  2383.         // No explicit color space
  2384.                     pOnePlane->planeSpace   = gxNoSpace;
  2385.         
  2386.         // No color set
  2387.                     pOnePlane->planeSet     = nil;
  2388.  
  2389.         // No profile specified
  2390.                     pOnePlane->planeProfile = nil;
  2391.                 }
  2392.             }
  2393.  
  2394.         }
  2395.  
  2396.     }
  2397.  
  2398.     return(noErr);
  2399.     
  2400. // EXCEPTION HANDLING
  2401. SendDownloadTable:
  2402. GetDownloadTable:
  2403.     DisposHandle((**hGlobals).draftTable);
  2404.     (**hGlobals).draftTable = nil;
  2405.     
  2406. FailedToLoadDraftTable:
  2407. Forward_GXSetupImageData:
  2408.     return(anErr);
  2409.     
  2410. } // SD_SetupImageData
  2411.  
  2412. /* ------------------------------------------------------------------------------------    */
  2413. OSErr SD_FetchDriverData(
  2414.     ResType            theType,
  2415.     short            theID,
  2416.     Handle*            theData)
  2417. {
  2418.  
  2419.     OSErr    anErr;
  2420.     
  2421.     anErr = Forward_GXFetchTaggedDriverData(theType, theID, theData);
  2422.     
  2423.     // do the translation at the proper DPI by modifying the old API
  2424.     // customization resource
  2425.     if ( (anErr   == noErr)    &&                 // got the resource okay
  2426.          (theType == 'cust')   &&                // it was a customization resource 
  2427.          (theID   == -8192)   )                    // with the old API id
  2428.         {
  2429.         long imagewriterOptions;
  2430.         
  2431.         if (!JobIsBest(&imagewriterOptions))
  2432.             {
  2433.             **((short**)theData)   = 72;
  2434.             **((short**)theData+1) = 72;
  2435.             }
  2436.         }
  2437.         
  2438.     return(anErr);
  2439.     
  2440. } // SD_FetchDriverData
  2441.  
  2442.  
  2443. /* ------------------------------------------------------------------------------------    */
  2444. OSErr SD_RenderPage(    gxFormat                theFormat,
  2445.                         gxShape                    thePage,
  2446.                         gxPageInfoRecord        *pageInfo,
  2447.                         gxRasterImageDataHdl    imageInfo)
  2448. /*
  2449.     The message sent to render an entire page.
  2450. */
  2451. {
  2452.  
  2453.     OSErr    theError = noErr;
  2454.  
  2455.     // if not text mode, do it the normal (raster) way
  2456.     if (GXGetJobFormatMode(GXGetJob()) != gxTextJobFormatMode) 
  2457.         {
  2458.         gxRectangle            paperSize;
  2459.         Str63                formLength;            // should be more than big enough for form skipping
  2460.         char                aNumber[8];
  2461.         char                len = 0;
  2462.         short                formLen;            // form length (in 144 dpi)
  2463.         short                i;
  2464.         
  2465.         
  2466.         // find out how big our paper is
  2467.         GXGetPaperTypeDimensions(GXGetFormatPaperType(theFormat), nil, &paperSize);
  2468.         
  2469.         // determine the left margin (in pixels)
  2470.         {
  2471.         SpecGlobalsHdl             hGlobals = GetMessageHandlerInstanceContext();
  2472.         SpecGlobalsPtr            pGlobals;
  2473.         gxRasterImageDataPtr    pImageData;
  2474.  
  2475.         // dereference for size and speed    
  2476.         pImageData     = *imageInfo;
  2477.         pGlobals = *hGlobals;
  2478.         paperSize.left += ff(18);        // ImageWriter's can't go tighter than .25 inch
  2479.         if (paperSize.left > 0)
  2480.             paperSize.left = 0;
  2481.         pGlobals->leftMargin     = FixedToInt(
  2482.                                     FixMul(-paperSize.left, 
  2483.                                         FixDiv(pImageData->hImageRes, ff(72))));
  2484.         
  2485.         // set this to be the top of form
  2486.         formLength[len++] = ESCAPE;
  2487.         formLength[len++] = 'v';
  2488.  
  2489.         // set the form length to be the size of the page iff ImageWriterII
  2490.         if (pGlobals->isImageWriterII)
  2491.             {
  2492.             formLength[len++] = ESCAPE;
  2493.             formLength[len++] = 'H';
  2494.             formLen = FixedToInt(FixMul(paperSize.bottom-paperSize.top, ff(2)) );    // length is set in 144 dpi
  2495.             NumToString(formLen, (unsigned char*)aNumber);
  2496.             for (i = 0; i < 4-aNumber[0]; ++i)
  2497.                 formLength[len++] = '0';
  2498.             for (i = 1; i <= aNumber[0]; ++i)
  2499.                 formLength[len++] = aNumber[i];
  2500.             }
  2501.         }
  2502.  
  2503.         // NOW: move over the top margin
  2504.         formLen = -FixedToInt( FixMul(paperSize.top, ff(2)) );
  2505.         
  2506.             // Forward line feed
  2507.             formLength[len++] = ESCAPE;
  2508.             formLength[len++] = 'f';
  2509.  
  2510.             // send multiples of 99
  2511.             if (formLen >= 99)
  2512.                 {
  2513.                 formLength[len++] = ESCAPE;
  2514.                 formLength[len++] = 'T';
  2515.                 formLength[len++] = '9';
  2516.                 formLength[len++] = '9';
  2517.                 while (formLen >= 99)
  2518.                     {
  2519.                     formLength[len++] = 0x0A;        // line feed
  2520.                     
  2521.                     formLen -= 99;
  2522.                     }
  2523.                 }
  2524.                 
  2525.             // send remaining line feeds
  2526.             if (formLen > 0)
  2527.                 {
  2528.                 formLength[len++] = ESCAPE;
  2529.                 formLength[len++] = 'T';
  2530.                 NumToString(formLen, (unsigned char*)aNumber);
  2531.                 if (aNumber[0] == 1)
  2532.                     {
  2533.                     formLength[len++] = '0';
  2534.                     formLength[len++] = aNumber[1];
  2535.                     }
  2536.                 else
  2537.                     {
  2538.                     formLength[len++] = aNumber[1];
  2539.                     formLength[len++] = aNumber[2];
  2540.                     }
  2541.                 formLength[len++] = 0x0A;        // line feed
  2542.                 }
  2543.  
  2544.         // we've got all of this data, now send it
  2545.         theError = Send_GXBufferData((char*)formLength, len, gxNoBufferOptions );
  2546.         nrequire(theError, SetFormLength);        
  2547.                 
  2548.         // continue with normal rendering
  2549.         theError = Forward_GXRenderPage(theFormat, thePage, pageInfo, imageInfo);
  2550.         } 
  2551.     else 
  2552.         {
  2553.         theError = PrintPageInDraftMode(thePage, imageInfo);
  2554.         }
  2555.  
  2556. failed_WrongShape:
  2557. SetFormLength:
  2558.     return(theError);
  2559.     
  2560. } // SD_RenderPage
  2561.  
  2562.  
  2563. //<FF>
  2564. /* ------------------------------------------------------------------------------------    */
  2565. /*    SPECIFIC DRIVER RASTER OVERRIDES                                                    */
  2566. /* ------------------------------------------------------------------------------------    */
  2567. OSErr SD_LineFeed (
  2568.     long *lineFeedSize,                         // amount to line feed by
  2569.     Ptr buffer, unsigned long    * bufferPos,     // data goes here
  2570.     gxRasterImageDataHdl hImageData)            // raster image data stuff
  2571. /*
  2572.     Message is sent to output paper advance commands to the printer
  2573. */
  2574. {
  2575.  
  2576.     OSErr    anErr;
  2577.     Boolean    amLowRes;
  2578.     long    actualLineFeed = *lineFeedSize;
  2579.  
  2580.     amLowRes = ((**hImageData).vImageRes == ff(72));
  2581.     // if we are in low res mode, we double the line feed size, as all ImageWriter 
  2582.     // line feed commands are expressed at 144 dpi.
  2583.     if (amLowRes)
  2584.         *lineFeedSize <<= 1;
  2585.     
  2586.     // optimize small motions (particularlly -1 followed by +1 with no data between)
  2587.     // into groups.  This gets rid of the "paper dance" for blank colors passes.
  2588.     {    
  2589.     SpecGlobalsHdl    hGlobals = GetMessageHandlerInstanceContext();
  2590.     SpecGlobalsPtr    pGlobals = *hGlobals;
  2591.     
  2592.     if (    (pGlobals->packagingOptions == kDoSmallLineFeeds) || 
  2593.             (*lineFeedSize < -1) || 
  2594.             (*lineFeedSize > 1) )
  2595.         {
  2596.         *lineFeedSize += pGlobals->lineFeeds;
  2597.         pGlobals->lineFeeds = 0;
  2598.         // do the line feed in the default way
  2599.         anErr = Forward_GXRasterLineFeed(lineFeedSize, buffer, bufferPos, hImageData);
  2600.         }
  2601.     else
  2602.         {
  2603.         pGlobals->lineFeeds += *lineFeedSize;
  2604.         *lineFeedSize = 0;
  2605.         anErr = noErr;
  2606.         }
  2607.     }
  2608.     
  2609.     // and if in low quality mode, we divide the result to make up for the multiplication
  2610.     // that we do above
  2611.     if (amLowRes)
  2612.         *lineFeedSize >>= 1;    
  2613.             
  2614.     return(anErr);
  2615.     
  2616. } // SD_LineFeed
  2617.  
  2618. //<FF>
  2619.  
  2620. //-------------------------------------------------------------------
  2621. // PrintThisBand
  2622. //
  2623. // Gets the render options collection, and tests the current printer
  2624. // band against it to see if it needs to draw this band
  2625. //-------------------------------------------------------------------
  2626.  
  2627. Boolean PrintThisBand ( short printerBand )
  2628. {
  2629.     Boolean                 displayPlane = true;
  2630.     OSErr                    theErr;
  2631.     CMYKRenderCollection     planes;
  2632.     Collection                 jobCollection;
  2633.     long                    itemSize = sizeof(CMYKRenderCollection);
  2634.     gxJob                    theJob;
  2635.     
  2636.     theJob = GXGetJob();
  2637.  
  2638.     jobCollection = GXGetJobCollection(theJob);
  2639.  
  2640.     theErr = GetCollectionItem( jobCollection, 
  2641.                                 kCMYKRenderCollectionType, kCMYKRenderCollectionID, 
  2642.                                 &itemSize, &planes);
  2643.     nrequire(theErr, FailedGetCollectionItem);
  2644.  
  2645.     if (!theErr)
  2646.     {
  2647.         switch (printerBand){
  2648.             case kYellowPass  : displayPlane = planes.yellowIsOn;
  2649.                 break;
  2650.             case kMagentaPass : displayPlane = planes.magentaIsOn;
  2651.                 break;
  2652.             case kCyanPass    : displayPlane = planes.cyanIsOn;
  2653.                 break;
  2654.             case kBlackPass   : displayPlane = planes.blackIsOn;
  2655.                 break;
  2656.         }
  2657.     }
  2658.  
  2659. FailedGetCollectionItem:
  2660.  
  2661.     return displayPlane;
  2662. }
  2663.  
  2664. //<FF>
  2665. /* ------------------------------------------------------------------------------------    */
  2666.  
  2667. // This macro stores one group into the pointer:
  2668. //    P = Pointer to fill into
  2669. //    G = Character for group
  2670. //    S = Length of group run in pixels
  2671.  
  2672. #define EMITGROUP(P, G, S)                    \
  2673.         P->cEscape = ESCAPE;                \
  2674.         P->cCommand = G;                    \
  2675.         Long2Dec(S, P->cLineLength);        
  2676.  
  2677. //<FF>
  2678. /* ------------------------------------------------------------------------------------    */
  2679.  
  2680. OSErr SD_PackageBitmap (
  2681.     gxRasterPackageBitmapRec    *pPackage,
  2682.     Ptr                         buffer,     // data goes here + bufferPos
  2683.     unsigned long                 *bufferPos,    // how much of the buffer already is full
  2684.     gxRasterImageDataHdl         hImageData)    // private image data
  2685. /*
  2686.     Packages a bitmap for the ImageWriter
  2687.     This routine is called in order to add your rotated and packaged pixel
  2688.     data to the buffer.  It is called once for each head pass.  This routine
  2689.     is pretty complex because it also does IW run length compression. 
  2690.  
  2691.     It has also been modified so it can handle color seperations. It does this by
  2692.     by comparing the color of the current pass to the render options collection.
  2693.     This is done by PrintThisBand().
  2694.     
  2695.     It must do the following:
  2696.         
  2697.     1)    Start filling the buffer from buffer+bufferPos.  Remember
  2698.         that this pointer may not be word aligned - so be careful
  2699.         assigning things into it.
  2700.         
  2701.     2)    If your printer does SetMargins, put a "fake" set of commands at
  2702.         the begining of the data.  Since most of the time you don't
  2703.         know the margins, you can save away the value of the bufferPos,
  2704.         and backpatch it after you have finished with the offscreen.
  2705.         SetMargins is used on printers that allow you to not send starting
  2706.         and ending whitespace.
  2707.         
  2708.     3)    Add in the rotated data for your printer.  The data to stuff starts
  2709.         at location startY in hOffscreen.  Stuff the bits from here until
  2710.         you reach startY+<your band size>, which is the size of your single
  2711.         band in this resolution mode.  Increment your number by 
  2712.         <your pass offset> + 1, which is the number of microspaces
  2713.         you will send between head passes to form this band.   Take care
  2714.         that you don't step off of the end of the offscreen in this operation,
  2715.         you may be called with startY at the end of the offscreen if the first part
  2716.         of the band is white.
  2717.         
  2718.         colorBand contains the color band which you should be stuffing, from
  2719.         1 to the number of color passes your printer needs (usually 4).
  2720.         Pack in the correct color band.  The packager will call you once
  2721.         for each color band, and correctly handle line feeds and backward
  2722.         line feeds to do the correct thing.  If your printer takes full
  2723.         RGB or CYMK data, I would define your number of colors to be
  2724.         1 and pack the full RGB or CYMK data with the one call to StuffBuffers.
  2725.         
  2726.         If you request kSendAllColors in your raster pack resource, then this
  2727.         message will always be called for all color passes, even those that
  2728.         do not have data on them.  For some printers, this is useful.  For the
  2729.         case of the ImageWriter, this option is not specified, so this message
  2730.         will only be sent for colors that actually have dirty bits within them.
  2731.         
  2732.     4)    Backpatch SetMargins from your saved value in step 2) now that you
  2733.         know the margins.
  2734.         
  2735.     5)    Increment bufferPos by the number of bytes you have
  2736.         added to the buffer.  Be sure to take into account the Set Margins
  2737.         command if you added one.
  2738.  
  2739.     
  2740. */
  2741. {
  2742. // #pragma unused (isColorDirty)
  2743.  
  2744.     OSErr                    anErr;                    // would you beleive we could make mistakes?
  2745.     ScanLinePtr                pTheScanLine;            // Pointer to the start of scan line data
  2746.     unsigned short            lastDirtyCol;            // Last dirty part of the scan line
  2747.     unsigned short            firstDirty;                // First dirty pixel
  2748.     unsigned short            lastDirty;                // Last dirty pixel
  2749.     Boolean                    bandIsDirty;            // Is this band dirty?
  2750.     unsigned short            numberBytesAdded;        // Number of bytes we have added to the row
  2751.     unsigned short            repeatCount;            // Number of times we have seen this bitmap
  2752.     
  2753.     register unsigned short    whichCol;                // Index into the scan line data
  2754.     register unsigned short    x,y;                    // Index values into the offscreen
  2755.         
  2756.     register Ptr            thePtr;                    // Pointer to each Y scanline
  2757.     register unsigned char    tempColumn;                // Placeholder for the working column
  2758.     unsigned char            lastColumn;                // What was in the contents of the last column?
  2759.     
  2760.     Ptr                        basePtr;                // Pointer to current X byte
  2761.     unsigned char            outputMask;                // Mask of bit to set in rotated image
  2762.     unsigned char            inputMask;                // Mask of bit to look at in X
  2763.     unsigned char            startingInputMask;        // Mask of first bit of interest
  2764.     unsigned short            yPointerOffset;            // Increment pointer by this to get to next scanline
  2765.     
  2766.     unsigned short            endY, endX, incrY;        // To remove loop invariants.
  2767.     unsigned short            packingColor;            // number of colors packing
  2768.     unsigned long             originalBufferPos;        // where we were in the buffer before we started;
  2769.     long                    originalLineFeeds;        // how many line feeds did we have before?
  2770.     SpecGlobalsHdl            hGlobals;
  2771.     SpecGlobalsPtr            pGlobals;
  2772.     SetMarginsPtr            marginBuffer;
  2773.  
  2774. // Get the globals
  2775.     hGlobals = GetMessageHandlerInstanceContext();
  2776.     pGlobals = *hGlobals;
  2777.     
  2778. // save away original position in order to do a restore should the band be clean
  2779.     originalBufferPos = *bufferPos;
  2780.     originalLineFeeds = pGlobals->lineFeeds;
  2781.  
  2782.     if (originalLineFeeds == 0)
  2783.     {
  2784.         anErr = noErr;
  2785.     }
  2786.     else
  2787.     {
  2788. // if we have any extra line feeds saved up, do them now!    
  2789.         pGlobals->lineFeeds = 0;
  2790.         pGlobals->packagingOptions = kDoSmallLineFeeds;
  2791.         anErr = Send_GXRasterLineFeed((long*)&originalLineFeeds, buffer, bufferPos, hImageData);
  2792.         pGlobals = *hGlobals;
  2793.         pGlobals->packagingOptions = kNoPackagingOptions;
  2794.     }
  2795.     nrequire(anErr, SendInitialLineFeeds);
  2796.     
  2797. // See if we need to print this color band
  2798.     if (   (  (*hImageData)->packagingInfo.colorPasses == 4)
  2799.         && (! PrintThisBand ( pPackage->colorBand )) )
  2800.         bandIsDirty = false;
  2801.     else
  2802.     {
  2803.  
  2804.     // Set color if ImageWriterII
  2805.         if ((**hGlobals).isImageWriterII)
  2806.         {
  2807.             pTheScanLine = (ScanLinePtr) (buffer + kSetMarginsSize + (*bufferPos));
  2808.             
  2809.     // Set color mode for this scan line, if needed
  2810.             pTheScanLine->cColorEscape        = ESCAPE;
  2811.             pTheScanLine->cSetColorCommand    = kSetColorCommand;
  2812.             
  2813.             packingColor = (*hImageData)->packagingInfo.colorPasses;
  2814.             if (packingColor == 4)
  2815.             {
  2816.                 switch (pPackage->colorBand)
  2817.                 {
  2818.                     case kYellowPass:
  2819.                         pTheScanLine->cColor    = '1';
  2820.                         startingInputMask = 0x10;
  2821.                         break;
  2822.                         
  2823.                     case kMagentaPass:
  2824.                         pTheScanLine->cColor    = '2';
  2825.                         startingInputMask = 0x20;
  2826.                         break;
  2827.                         
  2828.                     case kCyanPass:
  2829.                         pTheScanLine->cColor    = '3';
  2830.                         startingInputMask = 0x40;
  2831.                         break;
  2832.                         
  2833.                     case kBlackPass:
  2834.                         pTheScanLine->cColor    = '0';
  2835.                         startingInputMask = 0x80;
  2836.                         break;
  2837.                 
  2838.                 }
  2839.             }
  2840.             else
  2841.             {
  2842.                 pTheScanLine->cColor = '0';
  2843.                 startingInputMask = 0x80;
  2844.             }
  2845.         }
  2846.         else    // Backup to eliminate cColorEscape, cSetColorCommand and cColor
  2847.         {
  2848.             pTheScanLine = (ScanLinePtr) (buffer + kSetMarginsSize + (*bufferPos) - 3);
  2849.             packingColor = (*hImageData)->packagingInfo.colorPasses;
  2850.             startingInputMask = 0x80;
  2851.         }
  2852.  
  2853.     
  2854. // Start with the first bit in the offscreen 
  2855.         inputMask = startingInputMask;
  2856.         
  2857. // We start out with no dirty bits 
  2858.         firstDirty = 0;
  2859.         lastDirty = 0;
  2860.         bandIsDirty = false;
  2861.         
  2862. // Set our array index to zero 
  2863.         whichCol = 0;
  2864.         lastDirtyCol = 0;
  2865.         numberBytesAdded = 0;
  2866.         
  2867. // Set up RLL variables 
  2868.         repeatCount = 0;
  2869.         lastColumn = 0;
  2870.         
  2871. // Get the byte pointer for the start of this color band 
  2872.         basePtr = pPackage->bitmapToPackage->image;
  2873.         
  2874. // Get the byte pointer for the start of the first scan line  
  2875.         basePtr += pPackage->startRaster * pPackage->bitmapToPackage->rowBytes;
  2876.         
  2877. // Save away loop invariants 
  2878.         endY     = pPackage->startRaster + (*hImageData)->packagingInfo.headHeight;     // Ending scan line
  2879.         incrY     = (*hImageData)->packagingInfo.passOffset + 1;            // Number of scanlines to increment by
  2880.         endX     = pPackage->dirtyRect.right;                            // Ending X pos
  2881.         yPointerOffset = incrY * pPackage->bitmapToPackage->rowBytes;    // amount to add to the input
  2882.  
  2883. // pointer to move to the next scanline
  2884.         
  2885. // If the ending position is too large for the bitmap we have been given,
  2886. //    truncate it, so that we don't print garbage
  2887.         if (endY > pPackage->bitmapToPackage->height)
  2888.             endY = pPackage->bitmapToPackage->height;
  2889.         
  2890. // For the entire width of the offscreen, move a rolling mask along in the
  2891. // X direction, rotating up 8 bits of Y data per column.  In addition, compress
  2892. // runs of columns that are > 14 length. 
  2893.         for (x = 0; x < endX; x++)
  2894.         {        
  2895.     // The bits in this column are clear to begin with 
  2896.             tempColumn = 0;
  2897.             
  2898.     // Which byte to look at in the input buffer 
  2899.             thePtr = basePtr;
  2900.             
  2901.     //     Where to place the bit in the output. The ImageWriter takes the bit
  2902.     //  pattern upside down. 
  2903.             outputMask = 0x01;
  2904.             
  2905.     // Scan through this band, setting each of the 8 bits == the bit in that scan line 
  2906.             for (y = pPackage->startRaster; y < endY; y += incrY)
  2907.             {
  2908.     // If we have a bit in the input, rotate it into the output 
  2909.                 if ((*thePtr) & inputMask)
  2910.                     tempColumn |= outputMask;
  2911.                 
  2912.     // move onto next position in the output data                
  2913.                 outputMask <<= 1;
  2914.                 
  2915.     // move onto the next scan line in the input data
  2916.                 thePtr += yPointerOffset;
  2917.             } // for y
  2918.             
  2919.             
  2920.     // Save the column info  
  2921.             pTheScanLine->iTheData[whichCol] = tempColumn;
  2922.             
  2923.     // Get the next bit from the current pointer 
  2924.             inputMask >>= packingColor;
  2925.             if (!inputMask)
  2926.             {
  2927.     // If we run out of bits, get the next byte 
  2928.                 basePtr++;
  2929.             
  2930.     // And reset the bit mask to the first bit 
  2931.                 inputMask = startingInputMask;
  2932.             }
  2933.             
  2934.     // If we have some form of data 
  2935.             if (tempColumn != 0)
  2936.             {
  2937.                 if (!bandIsDirty)
  2938.                 {
  2939.     // This is the first dirty pixels we have so far 
  2940.                     bandIsDirty = true;
  2941.                     firstDirty = x;
  2942.                 }
  2943.             
  2944.     // This is also the last dirty pixels so far 
  2945.                 lastDirty = x;
  2946.             } // SetDirty
  2947.             
  2948.     // If we have some dirty bits 
  2949.             if (bandIsDirty)
  2950.             {
  2951.     // Move on to the next column 
  2952.                 whichCol++;
  2953.                 
  2954.     // If this is a dirty column, then it is the last one so far 
  2955.                 if (tempColumn != 0)
  2956.                     lastDirtyCol = whichCol;
  2957.                 
  2958.     // If we have a duplication, up the repeat count 
  2959.                 if (tempColumn == lastColumn) // if (false) // turn off repeat groups
  2960.                 {
  2961.                     repeatCount++;
  2962.                     if (repeatCount == 14)
  2963.                     {
  2964.     // Kick out the old group 
  2965.                         whichCol -= 14;
  2966.                         EMITGROUP(pTheScanLine, kGraphicsCommand, whichCol);
  2967.                         numberBytesAdded += whichCol + kGroupSize;
  2968.                         pTheScanLine = (ScanLinePtr)(((Ptr) pTheScanLine) +
  2969.                         whichCol + kGroupSize);
  2970.                         
  2971.                         whichCol = 1;
  2972.                         lastDirtyCol = 1;
  2973.                         pTheScanLine->iTheData[0] = tempColumn;
  2974.                     }
  2975.                 }
  2976.                 else
  2977.                 {
  2978.     // If we were repeating, emit the repeat group 
  2979.                     if (repeatCount >= 14)
  2980.                     {
  2981.                         EMITGROUP(pTheScanLine, kRepeatGroup, repeatCount);
  2982.                         numberBytesAdded += 1 + kGroupSize;
  2983.                         pTheScanLine = (ScanLinePtr) (((Ptr) pTheScanLine) +  1 + kGroupSize);
  2984.                         
  2985.                         whichCol = 1;
  2986.                         lastDirtyCol = 1;
  2987.                         pTheScanLine->iTheData[0] = tempColumn;
  2988.                     }
  2989.                     repeatCount = 0;
  2990.                     lastColumn = tempColumn;
  2991.                 }
  2992.                 
  2993.             } // BandIsDirty
  2994.             
  2995.         } // end of loop for width of bitmap
  2996.         
  2997.     }
  2998.  
  2999.  
  3000. // if we have a dirty band - emit the final bit of data we have packaged up 
  3001.     if (bandIsDirty)
  3002.     {            
  3003.     
  3004. // Set the margins to be the first and last dirty pixels in the scan line -
  3005. // the ImageWriter only does left margin optimization.
  3006.         {
  3007.         
  3008.     // Get the location for placing the set margin command 
  3009.             marginBuffer = (SetMarginsPtr) (buffer + (*bufferPos));
  3010.         
  3011.     // Stuff in the set margin command 
  3012.             marginBuffer->cEscape  = ESCAPE;
  3013.             marginBuffer->cCommand = kSetMarginsCommand;
  3014.         
  3015.     // convert left margin into ASCII and place it at the start of the buffer 
  3016.             Long2Dec((**hGlobals).leftMargin + firstDirty, (Ptr)(marginBuffer->cIndentDistance));
  3017.         }
  3018.         
  3019.     // Send the last group command 
  3020.         if (repeatCount < 14)
  3021.         {
  3022.         // Emit a normal group 
  3023.             EMITGROUP(pTheScanLine, kGraphicsCommand, lastDirtyCol);
  3024.             numberBytesAdded += lastDirtyCol + kGroupSize;
  3025.         }
  3026.         else
  3027.         {
  3028.         // Don't stuff a final repeat group if it's blank space 
  3029.  
  3030.             if (tempColumn != 0)
  3031.             {
  3032.  
  3033.         // Emit a repeat group 
  3034.                 EMITGROUP(pTheScanLine, kRepeatGroup, repeatCount);
  3035.                 numberBytesAdded += 1 + kGroupSize;
  3036.             }
  3037.         } // end of repeatCount < 14
  3038.         
  3039.         
  3040.     //    Increment the count of the buffer by bytes added for groups, plus
  3041.     //  the header, if any, plus the set margins command 
  3042.         (*bufferPos) += numberBytesAdded + kScanLineSize + kSetMarginsSize;
  3043.         
  3044.     // and put a <cr> at the end of the line
  3045.         *(char*)(buffer + (*bufferPos)) = 0x010D;
  3046.         (*bufferPos) += 1;
  3047.         
  3048.     } // bandIsDirty
  3049.     else
  3050.     {
  3051. // Band is not dirty, so don't output data as we didn't have any!
  3052.  
  3053.         *bufferPos = originalBufferPos;
  3054.     
  3055.     // restore original number of line feeds
  3056.         pGlobals = *hGlobals;
  3057.         pGlobals->lineFeeds = originalLineFeeds;
  3058.     } 
  3059.  
  3060. // always return your errors!
  3061. SendInitialLineFeeds:
  3062.     return(anErr);
  3063.  
  3064. } // SD_PackageBitmap
  3065.  
  3066.  
  3067. //===================================================================
  3068. //             Print dialog handling stuff 
  3069. //===================================================================
  3070.  
  3071. // Dialog panel items constants
  3072.  
  3073. #define kDitherRB   1
  3074. #define kHalfToneRB 2
  3075. #define k_Dth_DotPU 3
  3076. #define k_HT_DotShapePU 4
  3077. #define k_HT_AngleTE0   5
  3078. #define k_HT_FreqTE0    6
  3079. #define k_HT_AngleTE1   7
  3080. #define k_HT_FreqTE1    8
  3081. #define k_HT_AngleTE2   9
  3082. #define k_HT_FreqTE2    10
  3083. #define k_HT_AngleTE3   11
  3084. #define k_HT_FreqTE3    12
  3085. #define k_Dth_Box       20
  3086. #define k_HT_Box        21
  3087.  
  3088. //-------------------------------------------------------------------
  3089. // SD_JobPrintDialog
  3090. //
  3091. // overides : GXJobPrintDialog
  3092. //
  3093. // Called by the system when the  print dialog is being created.
  3094. // This gives us a chance to add out own panels. This done by
  3095. // SetUpPrintPanel.
  3096. //-------------------------------------------------------------------
  3097.  
  3098. OSErr SD_JobPrintDialog(gxDialogResult *dlogResult )
  3099. {
  3100.     OSErr theErr = noErr;
  3101.  
  3102.     theErr = SetUpPrintPanel( ); 
  3103.     
  3104.     if (!theErr)
  3105.         theErr = Forward_GXJobPrintDialog(dlogResult);
  3106.  
  3107.     return theErr;
  3108. }
  3109.  
  3110. //-------------------------------------------------------------------
  3111. // SD_HandlePanelEvent
  3112. //
  3113. // overides : HandlePanelEvent
  3114. //
  3115. // Messages are passed by the system to SD_HandlePanelEvent so it can
  3116. // do any special processing while the print panel is up. We use this
  3117. // to set up any custom items or gray fields, etc. Because we've 
  3118. // added two panels, we need to check from which panel the message
  3119. // has been passed. This can be found in gxPanelInfoRecord.panelResId 
  3120. //-------------------------------------------------------------------
  3121.  
  3122.  
  3123. OSErr SD_HandlePanelEvent( gxPanelInfoRecord *panelInfo )
  3124. {
  3125.     OSErr                   theErr = noErr;
  3126.     GrafPtr                 oldPort;
  3127.     DialogPtr               pDlg;
  3128.     CMYKRenderCollection     planes;
  3129.     Collection                 jobCollection;
  3130.     long                    itemSize = sizeof(CMYKRenderCollection);
  3131.     gxJob                    theJob;
  3132.  
  3133.     pDlg = panelInfo->pDlg;
  3134.  
  3135.     GetPort(&oldPort);
  3136.     SetPort(pDlg);
  3137.     
  3138.     switch (panelInfo->panelEvt)
  3139.     {
  3140.  
  3141.         case gxPanelOpenEvt:
  3142.  
  3143. // Every time a panel is opened, set up any items on it that may need setting.
  3144.             if (panelInfo->panelResId == kDitherPanelID)
  3145.                 OpenDitherPanel(pDlg, panelInfo->itemCount);
  3146.             break;
  3147.  
  3148.         case gxPanelHitEvt:
  3149.     
  3150. // If the user clicks the dither or half-tone buttons then we need to gray
  3151. // out items appropriately. As We're using a gxExtendedDITLType resource
  3152. // -'xdtl' to handle the collection, we don't need to worry about changing
  3153. // the state of the dialog box then writting back the collection. We get the
  3154. // collection so we can see if the state has changed, this saves on unneeded
  3155. // setting of dialog items states and possible flicker.
  3156.  
  3157.             if (panelInfo->panelResId == kDitherPanelID)
  3158.             {
  3159.                 theJob = GXGetJob();
  3160.                 jobCollection = GXGetJobCollection(theJob);
  3161.                 theErr = GetCollectionItem( jobCollection, 
  3162.                                             kCMYKRenderCollectionType, kCMYKRenderCollectionID, 
  3163.                                             &itemSize, &planes);
  3164.                 if (!theErr)
  3165.                     switch (panelInfo->itemHit - panelInfo->itemCount)
  3166.                     {
  3167.                         case kDitherRB:
  3168.                         case kHalfToneRB:
  3169.                                 GrayDitherDialog ( pDlg, panelInfo->itemCount,
  3170.                                                     planes.renderMode == kDitherIt );
  3171.                         break;
  3172.                     }
  3173.             }
  3174.             break;
  3175.     }
  3176.     
  3177.     SetPort(oldPort);    
  3178.  
  3179.     return theErr;
  3180. }
  3181.  
  3182. //-------------------------------------------------------------------
  3183. // SetUpPrintPanel
  3184. //
  3185. // This creates the render options collection and adds it to a print
  3186. // job.Then it adds two extra panels to the print panel. 
  3187. //-------------------------------------------------------------------
  3188.  
  3189. OSErr SetUpPrintPanel( void )
  3190. {
  3191.     OSErr                theErr = noErr;
  3192.     gxPanelSetupRecord   panelSetupRec;
  3193.     CMYKRenderCollection planesConfig;
  3194.     Collection           jobCollection;
  3195.     long                 itemSize = sizeof(CMYKRenderCollection);
  3196.  
  3197. //    Get the job collection and then try to find the
  3198. //    render collection item in there.
  3199.     
  3200.     jobCollection = GXGetJobCollection(GXGetJob());
  3201.  
  3202.     theErr = GetCollectionItem( jobCollection, 
  3203.                                 kCMYKRenderCollectionType, kCMYKRenderCollectionID, 
  3204.                                 &itemSize, &planesConfig);
  3205.  
  3206. //    If the collection item doesn’t yet exist, create a new
  3207. //    item, set it up with default values, and add it to the
  3208. //    job collection
  3209.     
  3210.     if (theErr == collectionItemNotFoundErr)
  3211.     {
  3212. // Turn all planes on
  3213.         planesConfig.cyanIsOn        = true;
  3214.         planesConfig.magentaIsOn    = true;
  3215.         planesConfig.yellowIsOn        = true;
  3216.         planesConfig.blackIsOn        = true;
  3217.  
  3218. // Print in half tone mode
  3219.         planesConfig.renderMode = kHalfToneIt;
  3220.  
  3221. // Put default values into the dither parameters
  3222.         planesConfig.ditherLevel  = 4;
  3223.  
  3224. // Put default values into the half tone parameters
  3225.         planesConfig.dotType      = gxRoundDot;
  3226.  
  3227.         planesConfig.angles   [kRenderOptsYellow] = 0x000F0000;
  3228.         planesConfig.frequency[kRenderOptsYellow] = 0x002D0000;
  3229.  
  3230.         planesConfig.angles   [kRenderOptsCyan] = 0x003C0000;
  3231.         planesConfig.frequency[kRenderOptsCyan] = 0x002D0000;
  3232.  
  3233.         planesConfig.angles   [kRenderOptsMagenta] = 0x00000000;
  3234.         planesConfig.frequency[kRenderOptsMagenta] = 0x002D0000;
  3235.  
  3236.         planesConfig.angles   [kRenderOptsBlack] = 0x002D0000;
  3237.         planesConfig.frequency[kRenderOptsBlack] = 0x002D0000;
  3238.  
  3239. // Add the new collection to the job
  3240.         theErr = AddCollectionItem    (    jobCollection,
  3241.                                         kCMYKRenderCollectionType,
  3242.                                         kCMYKRenderCollectionID,
  3243.                                         sizeof(CMYKRenderCollection),
  3244.                                         &planesConfig);
  3245.     }
  3246.  
  3247.     nrequire(theErr, GetSettings_Failed);
  3248.  
  3249.  
  3250. //    Set up the two panels: store the ID of the panel resource to use,
  3251. //    the resource file in which it is located, and the type of panel
  3252. //  that is being stored.
  3253.     
  3254.     panelSetupRec.panelResId     = kSeperationPanelID;
  3255.     panelSetupRec.resourceRefNum = GXGetMessageHandlerResFile();
  3256.     panelSetupRec.refCon         = 0;
  3257.     panelSetupRec.panelKind      = gxDriverPanel;
  3258.     theErr                       = GXSetupDialogPanel(&panelSetupRec);
  3259.  
  3260.     panelSetupRec.panelResId     = kDitherPanelID;
  3261.     panelSetupRec.resourceRefNum = GXGetMessageHandlerResFile();
  3262.     panelSetupRec.refCon         = 0;
  3263.     panelSetupRec.panelKind      = gxDriverPanel;
  3264.     theErr                       = GXSetupDialogPanel(&panelSetupRec);
  3265.  
  3266. GetSettings_Failed:
  3267.     return theErr;
  3268. }
  3269.  
  3270. //-------------------------------------------------------------------
  3271. // OpenDitherPanel
  3272. //
  3273. // Called by SD_HandlePanelEvent every time it is sent a 
  3274. // gxPanelOpenEvt for the kDitherPanelID. Need to get the collection
  3275. // and gray out any items as appropriate. Also add the frame user
  3276. // items.
  3277. //-------------------------------------------------------------------
  3278.  
  3279. OSErr OpenDitherPanel ( DialogPtr pDlg, short itemCount )
  3280. {
  3281.     CMYKRenderCollection planes;
  3282.     OSErr                theErr = noErr;
  3283.     long                 itemSize = sizeof(CMYKRenderCollection);
  3284.     Collection           jobCollection;
  3285.     gxJob                 theJob;
  3286.     Handle               hItem;
  3287.     Rect                 itemRect;
  3288.     short                itemType;
  3289.  
  3290. // Get the job
  3291.     theJob = GXGetJob();
  3292.  
  3293. // Get the collection
  3294.     jobCollection = GXGetJobCollection(theJob);
  3295.  
  3296. // Get the render options collection
  3297.     theErr = GetCollectionItem( jobCollection, 
  3298.                                 kCMYKRenderCollectionType, kCMYKRenderCollectionID, 
  3299.                                 &itemSize, &planes);
  3300.     nrequire(theErr, FailedGetCollectionItem);
  3301.  
  3302. // Gray out the items depending on the render mode
  3303.     GrayDitherDialog ( pDlg, itemCount,
  3304.                         planes.renderMode == kDitherIt );
  3305.  
  3306. // Add the frame items
  3307.     GetDItem(pDlg, itemCount + k_Dth_Box, &itemType, &hItem, &itemRect);
  3308.     SetDItem(pDlg, itemCount + k_Dth_Box, itemType, (Handle)DrawBoundBox, &itemRect);
  3309.  
  3310.     GetDItem(pDlg, itemCount + k_HT_Box, &itemType, &hItem, &itemRect);
  3311.     SetDItem(pDlg, itemCount + k_HT_Box, itemType, (Handle)DrawBoundBox, &itemRect);
  3312.  
  3313.  
  3314. FailedGetCollectionItem:
  3315.     return theErr;
  3316. }
  3317.  
  3318.  
  3319. //-------------------------------------------------------------------
  3320. // SetDialogCtrlGray
  3321. //
  3322. // Sets a control dialog item to gray.
  3323. //-------------------------------------------------------------------
  3324.  
  3325. void SetDialogCtrlGray ( DialogPtr pDlg, short theItem, Boolean isEnable)
  3326. {
  3327.     Handle             hItem;
  3328.     Rect               itemRect;
  3329.     short              itemType;
  3330.  
  3331.     GetDItem(pDlg, theItem, &itemType, &hItem, &itemRect);
  3332.     if (isEnable)
  3333.         HiliteControl ((ControlHandle)hItem, 0);
  3334.     else
  3335.         HiliteControl ((ControlHandle)hItem, 255);
  3336. }
  3337.  
  3338. //-------------------------------------------------------------------
  3339. // GrayDitherDialog
  3340. //
  3341. // Gray out unused items in the hilite control panel dependent on
  3342. // whether the dialog is half-tonning or drawing in color.
  3343. //-------------------------------------------------------------------
  3344.  
  3345. void GrayDitherDialog ( DialogPtr pDlg, short itemCount, Boolean isDither)
  3346. {
  3347.     if (isDither)
  3348.     {
  3349.         SetDialogCtrlGray ( pDlg, itemCount + k_Dth_DotPU,   true);
  3350.         SetDialogCtrlGray ( pDlg, itemCount + k_HT_DotShapePU, false);
  3351.     }
  3352.     else
  3353.     {
  3354.         SetDialogCtrlGray ( pDlg, itemCount + k_Dth_DotPU,   false);
  3355.         SetDialogCtrlGray ( pDlg, itemCount + k_HT_DotShapePU, true);
  3356.     }
  3357. }
  3358.  
  3359. //-------------------------------------------------------------------
  3360. // DrawBoundBox
  3361. //
  3362. // Draws a Rectangle user item in a dialog
  3363. //-------------------------------------------------------------------
  3364.  
  3365. pascal void DrawBoundBox( WindowPtr theWindow, short theItem )
  3366. {
  3367.     Handle hItem;
  3368.     Rect   itemRect;
  3369.     short  itemType;
  3370.  
  3371.     GetDItem(theWindow, theItem, &itemType, &hItem, &itemRect);
  3372.     FrameRect ( &itemRect );
  3373. }
  3374.  
  3375.